4 Commits

Author SHA1 Message Date
8cf6979f90 _some prog with dynamic linking perhaps
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2026-03-15 22:45:36 +02:00
1ff4ac0402 _maybe prog, trying static linking 2026-03-14 15:50:15 +02:00
801f0f7432 _some prog, needs aot for corlib 2026-03-14 15:50:15 +02:00
8b605dff89 _baseline emscripten build 2026-03-14 15:49:23 +02:00
351 changed files with 2713 additions and 6939 deletions

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Thanks for taking the time to fill out this bug report! Please attach a minimal reproduction project if available! Thanks for taking the time to fill out this bug report! Please attach any minimal reproduction projects!
- type: textarea - type: textarea
id: description-area id: description-area
attributes: attributes:
@@ -17,19 +17,19 @@ body:
id: steps-area id: steps-area
attributes: attributes:
label: Steps to reproduce label: Steps to reproduce
description: Please provide reproduction steps if available. description: Please provide reproduction steps if possible.
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
id: version id: version
attributes: attributes:
label: Version label: Version
description: What version of Flax did you experience the bug in? description: What version of Flax are you running?
options: options:
- '1.8'
- '1.9' - '1.9'
- '1.10' - '1.10'
- '1.11' - '1.11'
- '1.12'
- master branch - master branch
default: 3 default: 3
validations: validations:

View File

@@ -5,7 +5,7 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Thank you for taking the time to submit this feature request! Thanks for taking the time to fill out a feature request!
- type: textarea - type: textarea
id: description-area id: description-area
attributes: attributes:
@@ -17,6 +17,6 @@ body:
id: benefits-area id: benefits-area
attributes: attributes:
label: Benefits label: Benefits
description: Please list what benefits this feature would provide to the engine! description: Please provide what benefits this feature would provide to the engine!
validations: validations:
required: true required: true

1
.github/data/bt.sh vendored
View File

@@ -9,7 +9,6 @@ gdb -q --batch \
-ex 'handle SIGUSR1 nostop pass' \ -ex 'handle SIGUSR1 nostop pass' \
-ex 'handle SIGUSR2 nostop pass' \ -ex 'handle SIGUSR2 nostop pass' \
-ex 'handle SIGCHLD nostop pass' \ -ex 'handle SIGCHLD nostop pass' \
-ex 'handle SIG34 nostop pass' \
-ex 'set print thread-events off' \ -ex 'set print thread-events off' \
-return-child-result \ -return-child-result \
-ex 'run' \ -ex 'run' \

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env: env:
DOTNET_NOLOGO: true DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs: jobs:
@@ -20,7 +19,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Setup .NET Workload - name: Setup .NET Workload
run: | run: |
dotnet workload install android dotnet workload install android
@@ -34,7 +33,4 @@ jobs:
git lfs pull git lfs pull
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame .\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env: env:
DOTNET_NOLOGO: true DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs: jobs:
@@ -20,7 +19,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Print .NET info - name: Print .NET info
run: | run: |
dotnet --info dotnet --info
@@ -31,9 +30,6 @@ jobs:
git lfs pull git lfs pull
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor .\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
# Game # Game
@@ -48,7 +44,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Print .NET info - name: Print .NET info
run: | run: |
dotnet --info dotnet --info
@@ -59,7 +55,4 @@ jobs:
git lfs pull git lfs pull
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame .\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=8 -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame

View File

@@ -7,7 +7,6 @@ on:
env: env:
DOTNET_NOLOGO: true DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60' GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
jobs: jobs:
@@ -28,16 +27,13 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Print .NET info - name: Print .NET info
run: | run: |
dotnet --info dotnet --info
dotnet workload --info dotnet workload --info
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8 .\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -64,16 +60,13 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Print .NET info - name: Print .NET info
run: | run: |
dotnet --info dotnet --info
dotnet workload --info dotnet workload --info
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8 .\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output -dotnet=8
- name: Upload - name: Upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4

View File

@@ -4,7 +4,6 @@ on: [push, pull_request]
env: env:
DOTNET_NOLOGO: true DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false DOTNET_CLI_TELEMETRY_OPTOUT: false
DOTNET_ROLL_FORWARD: 'minor'
jobs: jobs:
@@ -57,7 +56,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 8.0.419 dotnet-version: 8.0.x
- name: Print .NET info - name: Print .NET info
run: | run: |
dotnet --info dotnet --info
@@ -68,9 +67,6 @@ jobs:
git lfs pull git lfs pull
- name: Build - name: Build
run: | run: |
PowerShell "(Get-Content global.json).Replace('latestMajor', 'minor') | Set-Content global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/global.json).Replace('latestMajor', 'minor') | Set-Content Source/Tools/Flax.Build/global.json"
PowerShell "(Get-Content Source/Tools/Flax.Build/Flax.Build.csproj).Replace('LatestMajor', 'Minor') | Set-Content Source/Tools/Flax.Build/Flax.Build.csproj"
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=8 .\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=8
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget .\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo

View File

@@ -1,4 +1,4 @@
# Redirect to our own Git LFS server # Redirect to our own Git LFS server
[lfs] [lfs]
url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs" #url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
locksverify = false locksverify = false

Binary file not shown.

View File

@@ -337,6 +337,7 @@ VertexOutput VS_SplineModel(ModelInput input)
// Apply world position offset per-vertex // Apply world position offset per-vertex
#if USE_POSITION_OFFSET #if USE_POSITION_OFFSET
output.Geometry.WorldPosition += material.PositionOffset; output.Geometry.WorldPosition += material.PositionOffset;
output.Geometry.PrevWorldPosition += material.PositionOffset;
output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix); output.Position = PROJECT_POINT(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
#endif #endif

Binary file not shown.

View File

@@ -4,7 +4,7 @@
"Major": 1, "Major": 1,
"Minor": 12, "Minor": 12,
"Revision": 0, "Revision": 0,
"Build": 6910 "Build": 6908
}, },
"Company": "Flax", "Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.", "Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
@@ -14,14 +14,6 @@
"UseCSharp": true, "UseCSharp": true,
"UseLargeWorlds": false, "UseLargeWorlds": false,
"UseDotNet": true, "UseDotNet": true,
"Windows": { "UseSDL": true
"UseSDL": false,
},
"Mac": {
"UseSDL": false,
},
"Linux": {
"UseSDL": true,
},
} }
} }

View File

@@ -19,7 +19,7 @@ namespace FlaxEditor.Content.GUI
/// <summary> /// <summary>
/// Gets the target node. /// Gets the target node.
/// </summary> /// </summary>
public ContentFolderTreeNode TargetNode { get; } public ContentTreeNode TargetNode { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContentNavigationButton"/> class. /// Initializes a new instance of the <see cref="ContentNavigationButton"/> class.
@@ -28,7 +28,7 @@ namespace FlaxEditor.Content.GUI
/// <param name="x">The x position.</param> /// <param name="x">The x position.</param>
/// <param name="y">The y position.</param> /// <param name="y">The y position.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
public ContentNavigationButton(ContentFolderTreeNode targetNode, float x, float y, float height) public ContentNavigationButton(ContentTreeNode targetNode, float x, float y, float height)
: base(x, y, height) : base(x, y, height)
{ {
TargetNode = targetNode; TargetNode = targetNode;
@@ -147,7 +147,7 @@ namespace FlaxEditor.Content.GUI
ClearItems(); ClearItems();
foreach (var child in Target.TargetNode.Children) foreach (var child in Target.TargetNode.Children)
{ {
if (child is ContentFolderTreeNode node) if (child is ContentTreeNode node)
{ {
if (node.Folder.VisibleInHierarchy) // Respect the filter set by ContentFilterConfig.Filter(...) if (node.Folder.VisibleInHierarchy) // Respect the filter set by ContentFilterConfig.Filter(...)
AddItem(node.Folder.ShortName); AddItem(node.Folder.ShortName);
@@ -180,7 +180,7 @@ namespace FlaxEditor.Content.GUI
var item = _items[index]; var item = _items[index];
foreach (var child in Target.TargetNode.Children) foreach (var child in Target.TargetNode.Children)
{ {
if (child is ContentFolderTreeNode node && node.Folder.ShortName == item) if (child is ContentTreeNode node && node.Folder.ShortName == item)
{ {
Editor.Instance.Windows.ContentWin.Navigate(node); Editor.Instance.Windows.ContentWin.Navigate(node);
return; return;

View File

@@ -59,7 +59,7 @@ namespace FlaxEditor.Content
/// <summary> /// <summary>
/// Gets the content node. /// Gets the content node.
/// </summary> /// </summary>
public ContentFolderTreeNode Node { get; } public ContentTreeNode Node { get; }
/// <summary> /// <summary>
/// The subitems of this folder. /// The subitems of this folder.
@@ -72,7 +72,7 @@ namespace FlaxEditor.Content
/// <param name="type">The folder type.</param> /// <param name="type">The folder type.</param>
/// <param name="path">The path to the item.</param> /// <param name="path">The path to the item.</param>
/// <param name="node">The folder parent node.</param> /// <param name="node">The folder parent node.</param>
internal ContentFolder(ContentFolderType type, string path, ContentFolderTreeNode node) internal ContentFolder(ContentFolderType type, string path, ContentTreeNode node)
: base(path) : base(path)
{ {
FolderType = type; FolderType = type;
@@ -118,7 +118,7 @@ namespace FlaxEditor.Content
get get
{ {
var hasParentFolder = ParentFolder != null; var hasParentFolder = ParentFolder != null;
var isContentFolder = Node is MainContentFolderTreeNode; var isContentFolder = Node is MainContentTreeNode;
return hasParentFolder && !isContentFolder; return hasParentFolder && !isContentFolder;
} }
} }

View File

@@ -1,433 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.SceneGraph;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content;
/// <summary>
/// Content folder tree node.
/// </summary>
/// <seealso cref="TreeNode" />
public class ContentFolderTreeNode : TreeNode
{
private DragItems _dragOverItems;
private DragActors _dragActors;
private List<Rectangle> _highlights;
/// <summary>
/// The folder.
/// </summary>
protected ContentFolder _folder;
/// <summary>
/// Whether this node can be deleted.
/// </summary>
public virtual bool CanDelete => true;
/// <summary>
/// Whether this node can be duplicated.
/// </summary>
public virtual bool CanDuplicate => true;
/// <summary>
/// Gets the content folder item.
/// </summary>
public ContentFolder Folder => _folder;
/// <summary>
/// Gets the type of the folder.
/// </summary>
public ContentFolderType FolderType => _folder.FolderType;
/// <summary>
/// Returns true if that folder can import/manage scripts.
/// </summary>
public bool CanHaveScripts => _folder.CanHaveScripts;
/// <summary>
/// Returns true if that folder can import/manage assets.
/// </summary>
/// <returns>True if can contain assets for project, otherwise false</returns>
public bool CanHaveAssets => _folder.CanHaveAssets;
/// <summary>
/// Gets the parent node.
/// </summary>
public ContentFolderTreeNode ParentNode => Parent as ContentFolderTreeNode;
/// <summary>
/// Gets the folder path.
/// </summary>
public string Path => _folder.Path;
/// <summary>
/// Gets the navigation button label.
/// </summary>
public virtual string NavButtonLabel => _folder.ShortName;
/// <summary>
/// Initializes a new instance of the <see cref="ContentFolderTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="path">The folder path.</param>
public ContentFolderTreeNode(ContentFolderTreeNode parent, string path)
: this(parent, parent?.FolderType ?? ContentFolderType.Other, path)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentFolderTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
protected ContentFolderTreeNode(ContentFolderTreeNode parent, ContentFolderType type, string path)
: base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;
if (parent != null)
{
Folder.ParentFolder = parent.Folder;
Parent = parent;
}
IconColor = Color.Transparent; // Hide default icon, we draw scaled icon manually
UpdateCustomArrowRect();
Editor.Instance?.Windows?.ContentWin?.TryAutoExpandContentNode(this);
}
/// <summary>
/// Updates the custom arrow rectangle so it stays aligned with the current layout.
/// </summary>
private void UpdateCustomArrowRect()
{
var contentWindow = Editor.Instance?.Windows?.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var arrowSize = Mathf.Clamp(12.0f * scale, 10.0f, 20.0f);
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
// Use the current text layout, not just cached values.
var textRect = TextRect;
var iconLeft = textRect.Left - iconSize - 2.0f;
var x = Mathf.Max(iconLeft - arrowSize - 2.0f, 0.0f);
var y = Mathf.Max((HeaderHeight - arrowSize) * 0.5f, 0.0f);
CustomArrowRect = new Rectangle(x, y, arrowSize, arrowSize);
}
/// <inheritdoc />
public override void PerformLayout(bool force = false)
{
base.PerformLayout(force);
UpdateCustomArrowRect();
}
/// <summary>
/// Shows the rename popup for the item.
/// </summary>
public void StartRenaming()
{
if (!_folder.CanRename)
return;
// Start renaming the folder
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(false);
var dialog = RenamePopup.Show(this, TextRect, _folder.ShortName, false);
dialog.Tag = _folder;
dialog.Renamed += popup =>
{
Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text);
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true);
};
dialog.Closed += popup => { Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); };
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
// Update itself
bool isThisVisible;
if (noFilter)
{
// Clear filter
_highlights?.Clear();
isThisVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
// Update highlights
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isThisVisible = true;
}
else
{
// Hide
_highlights?.Clear();
isThisVisible = false;
}
}
// Update children
bool isAnyChildVisible = false;
for (int i = 0; i < _children.Count; i++)
{
if (_children[i] is ContentFolderTreeNode child)
{
child.UpdateFilter(filterText);
isAnyChildVisible |= child.Visible;
}
else if (_children[i] is ContentItemTreeNode itemNode)
{
itemNode.UpdateFilter(filterText);
isAnyChildVisible |= itemNode.Visible;
}
}
if (!noFilter)
{
bool isExpanded = isAnyChildVisible;
if (isExpanded)
Expand(true);
else
Collapse(true);
}
Visible = isThisVisible | isAnyChildVisible;
}
/// <inheritdoc />
public override int Compare(Control other)
{
if (other is ContentItemTreeNode)
return -1;
if (other is ContentFolderTreeNode otherNode)
return string.Compare(Text, otherNode.Text, StringComparison.Ordinal);
return base.Compare(other);
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
// Draw all highlights
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
var contentWindow = Editor.Instance.Windows.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var icon = IsExpanded ? Editor.Instance.Icons.FolderOpen32 : Editor.Instance.Icons.FolderClosed32;
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
var iconRect = new Rectangle(TextRect.Left - iconSize - 2.0f, (HeaderHeight - iconSize) * 0.5f, iconSize, iconSize);
Render2D.DrawSprite(icon, iconRect);
}
/// <inheritdoc />
public override void OnDestroy()
{
// Delete folder item
_folder.Dispose();
base.OnDestroy();
}
/// <inheritdoc />
protected override void OnExpandedChanged()
{
base.OnExpandedChanged();
Editor.Instance?.Windows?.ContentWin?.OnContentTreeNodeExpandedChanged(this, IsExpanded);
}
private DragDropEffect GetDragEffect(DragData data)
{
if (_dragActors != null && _dragActors.HasValidDrag)
return DragDropEffect.Move;
if (data is DragDataFiles)
{
if (_folder.CanHaveAssets)
return DragDropEffect.Copy;
}
else
{
if (_dragOverItems != null && _dragOverItems.HasValidDrag)
return DragDropEffect.Move;
}
return DragDropEffect.None;
}
private bool ValidateDragItem(ContentItem item)
{
// Reject itself and any parent
return item != _folder && !item.Find(_folder);
}
private bool ValidateDragActors(ActorNode actor)
{
return actor.CanCreatePrefab && _folder.CanHaveAssets;
}
private void ImportActors(DragActors actors)
{
Select();
foreach (var actorNode in actors.Objects)
{
var actor = actorNode.Actor;
if (actors.Objects.Contains(actorNode.ParentNode as ActorNode))
continue;
Editor.Instance.Prefabs.CreatePrefab(actor, false);
}
Editor.Instance.Windows.ContentWin.RefreshView();
}
/// <inheritdoc />
protected override DragDropEffect OnDragEnterHeader(DragData data)
{
if (data is DragDataFiles)
return _folder.CanHaveAssets ? DragDropEffect.Copy : DragDropEffect.None;
if (_dragActors == null)
_dragActors = new DragActors(ValidateDragActors);
if (_dragActors.OnDragEnter(data))
return DragDropEffect.Move;
if (_dragOverItems == null)
_dragOverItems = new DragItems(ValidateDragItem);
_dragOverItems.OnDragEnter(data);
return GetDragEffect(data);
}
/// <inheritdoc />
protected override DragDropEffect OnDragMoveHeader(DragData data)
{
if (data is DragDataFiles)
return _folder.CanHaveAssets ? DragDropEffect.Copy : DragDropEffect.None;
if (_dragActors != null && _dragActors.HasValidDrag)
return DragDropEffect.Move;
return GetDragEffect(data);
}
/// <inheritdoc />
protected override void OnDragLeaveHeader()
{
_dragOverItems?.OnDragLeave();
_dragActors?.OnDragLeave();
base.OnDragLeaveHeader();
}
/// <inheritdoc />
protected override DragDropEffect OnDragDropHeader(DragData data)
{
var result = DragDropEffect.None;
// Check if drop element or files
if (data is DragDataFiles files)
{
// Import files
Editor.Instance.ContentImporting.Import(files.Files, _folder);
result = DragDropEffect.Copy;
Expand();
}
else if (_dragActors != null && _dragActors.HasValidDrag)
{
ImportActors(_dragActors);
_dragActors.OnDragDrop();
result = DragDropEffect.Move;
Expand();
}
else if (_dragOverItems != null && _dragOverItems.HasValidDrag)
{
// Move items
Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, _folder);
result = DragDropEffect.Move;
Expand();
}
_dragOverItems?.OnDragDrop();
return result;
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(_folder));
}
/// <inheritdoc />
protected override void OnLongPress()
{
Select();
StartRenaming();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.F2:
StartRenaming();
return true;
case KeyboardKeys.Delete:
if (Folder.Exists && CanDelete)
Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
{
switch (key)
{
case KeyboardKeys.D:
if (Folder.Exists && CanDuplicate)
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
}
return base.OnKeyDown(key);
}
}

View File

@@ -1,224 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using FlaxEditor.Content.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content;
/// <summary>
/// Tree node for non-folder content items.
/// </summary>
public sealed class ContentItemTreeNode : TreeNode, IContentItemOwner
{
private List<Rectangle> _highlights;
/// <summary>
/// The content item.
/// </summary>
public ContentItem Item { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ContentItemTreeNode"/> class.
/// </summary>
/// <param name="item">The content item.</param>
public ContentItemTreeNode(ContentItem item)
: base(false, Editor.Instance.Icons.Document128, Editor.Instance.Icons.Document128)
{
Item = item ?? throw new ArgumentNullException(nameof(item));
UpdateDisplayedName();
IconColor = Color.Transparent; // Reserve icon space but draw custom thumbnail.
Item.AddReference(this);
}
private static SpriteHandle GetIcon(ContentItem item)
{
if (item == null)
return SpriteHandle.Invalid;
var icon = item.Thumbnail;
if (!icon.IsValid)
icon = item.DefaultThumbnail;
if (!icon.IsValid)
icon = Editor.Instance.Icons.Document128;
return icon;
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
bool isVisible;
if (noFilter)
{
_highlights?.Clear();
isVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isVisible = true;
}
else
{
_highlights?.Clear();
isVisible = false;
}
}
Visible = isVisible;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
var icon = GetIcon(Item);
if (icon.IsValid)
{
var contentWindow = Editor.Instance.Windows.ContentWin;
var scale = contentWindow != null && contentWindow.IsTreeOnlyMode ? contentWindow.View.ViewScale : 1.0f;
var iconSize = Mathf.Clamp(16.0f * scale, 12.0f, 28.0f);
var textRect = TextRect;
var iconRect = new Rectangle(textRect.Left - iconSize - 2.0f, (HeaderHeight - iconSize) * 0.5f, iconSize, iconSize);
Render2D.DrawSprite(icon, iconRect);
}
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
}
/// <inheritdoc />
protected override bool OnMouseDoubleClickHeader(ref Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
{
Editor.Instance.Windows.ContentWin.Open(Item);
return true;
}
return base.OnMouseDoubleClickHeader(ref location, button);
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.Return:
Editor.Instance.Windows.ContentWin.Open(Item);
return true;
case KeyboardKeys.F2:
Editor.Instance.Windows.ContentWin.Rename(Item);
return true;
case KeyboardKeys.Delete:
Editor.Instance.Windows.ContentWin.Delete(Item);
return true;
}
}
return base.OnKeyDown(key);
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(Item));
}
/// <inheritdoc />
public override bool OnShowTooltip(out string text, out Float2 location, out Rectangle area)
{
Item.UpdateTooltipText();
TooltipText = Item.TooltipText;
return base.OnShowTooltip(out text, out location, out area);
}
/// <inheritdoc />
void IContentItemOwner.OnItemDeleted(ContentItem item)
{
}
/// <inheritdoc />
void IContentItemOwner.OnItemRenamed(ContentItem item)
{
UpdateDisplayedName();
}
/// <inheritdoc />
void IContentItemOwner.OnItemReimported(ContentItem item)
{
}
/// <inheritdoc />
void IContentItemOwner.OnItemDispose(ContentItem item)
{
}
/// <inheritdoc />
public override int Compare(Control other)
{
if (other is ContentFolderTreeNode)
return 1;
if (other is ContentItemTreeNode otherItem)
return ApplySortOrder(string.Compare(Text, otherItem.Text, StringComparison.InvariantCulture));
return base.Compare(other);
}
/// <inheritdoc />
public override void OnDestroy()
{
Item.RemoveReference(this);
base.OnDestroy();
}
/// <summary>
/// Updates the text of the node.
/// </summary>
public void UpdateDisplayedName()
{
var contentWindow = Editor.Instance?.Windows?.ContentWin;
var showExtensions = contentWindow?.View?.ShowFileExtensions ?? true;
Text = Item.ShowFileExtension || showExtensions ? Item.FileName : Item.ShortName;
}
private static SortType GetSortType()
{
return Editor.Instance?.Windows?.ContentWin?.CurrentSortType ?? SortType.AlphabeticOrder;
}
private static int ApplySortOrder(int result)
{
return GetSortType() == SortType.AlphabeticReverse ? -result : result;
}
}

View File

@@ -0,0 +1,333 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Content
{
/// <summary>
/// Content folder tree node.
/// </summary>
/// <seealso cref="TreeNode" />
public class ContentTreeNode : TreeNode
{
private DragItems _dragOverItems;
private List<Rectangle> _highlights;
/// <summary>
/// The folder.
/// </summary>
protected ContentFolder _folder;
/// <summary>
/// Whether this node can be deleted.
/// </summary>
public virtual bool CanDelete => true;
/// <summary>
/// Whether this node can be duplicated.
/// </summary>
public virtual bool CanDuplicate => true;
/// <summary>
/// Gets the content folder item.
/// </summary>
public ContentFolder Folder => _folder;
/// <summary>
/// Gets the type of the folder.
/// </summary>
public ContentFolderType FolderType => _folder.FolderType;
/// <summary>
/// Returns true if that folder can import/manage scripts.
/// </summary>
public bool CanHaveScripts => _folder.CanHaveScripts;
/// <summary>
/// Returns true if that folder can import/manage assets.
/// </summary>
/// <returns>True if can contain assets for project, otherwise false</returns>
public bool CanHaveAssets => _folder.CanHaveAssets;
/// <summary>
/// Gets the parent node.
/// </summary>
public ContentTreeNode ParentNode => Parent as ContentTreeNode;
/// <summary>
/// Gets the folder path.
/// </summary>
public string Path => _folder.Path;
/// <summary>
/// Gets the navigation button label.
/// </summary>
public virtual string NavButtonLabel => _folder.ShortName;
/// <summary>
/// Initializes a new instance of the <see cref="ContentTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="path">The folder path.</param>
public ContentTreeNode(ContentTreeNode parent, string path)
: this(parent, parent?.FolderType ?? ContentFolderType.Other, path)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentTreeNode"/> class.
/// </summary>
/// <param name="parent">The parent node.</param>
/// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param>
protected ContentTreeNode(ContentTreeNode parent, ContentFolderType type, string path)
: base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;
if (parent != null)
{
Folder.ParentFolder = parent.Folder;
Parent = parent;
}
IconColor = Style.Current.Foreground;
}
/// <summary>
/// Shows the rename popup for the item.
/// </summary>
public void StartRenaming()
{
if (!_folder.CanRename)
return;
// Start renaming the folder
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(false);
var dialog = RenamePopup.Show(this, TextRect, _folder.ShortName, false);
dialog.Tag = _folder;
dialog.Renamed += popup =>
{
Editor.Instance.Windows.ContentWin.Rename((ContentFolder)popup.Tag, popup.Text);
Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true);
};
dialog.Closed += popup => { Editor.Instance.Windows.ContentWin.ScrollingOnTreeView(true); };
}
/// <summary>
/// Updates the query search filter.
/// </summary>
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
bool noFilter = string.IsNullOrWhiteSpace(filterText);
// Update itself
bool isThisVisible;
if (noFilter)
{
// Clear filter
_highlights?.Clear();
isThisVisible = true;
}
else
{
var text = Text;
if (QueryFilterHelper.Match(filterText, text, out QueryFilterHelper.Range[] ranges))
{
// Update highlights
if (_highlights == null)
_highlights = new List<Rectangle>(ranges.Length);
else
_highlights.Clear();
var style = Style.Current;
var font = style.FontSmall;
var textRect = TextRect;
for (int i = 0; i < ranges.Length; i++)
{
var start = font.GetCharPosition(text, ranges[i].StartIndex);
var end = font.GetCharPosition(text, ranges[i].EndIndex);
_highlights.Add(new Rectangle(start.X + textRect.X, textRect.Y, end.X - start.X, textRect.Height));
}
isThisVisible = true;
}
else
{
// Hide
_highlights?.Clear();
isThisVisible = false;
}
}
// Update children
bool isAnyChildVisible = false;
for (int i = 0; i < _children.Count; i++)
{
if (_children[i] is ContentTreeNode child)
{
child.UpdateFilter(filterText);
isAnyChildVisible |= child.Visible;
}
}
bool isExpanded = isAnyChildVisible;
if (isExpanded)
{
Expand(true);
}
else
{
Collapse(true);
}
Visible = isThisVisible | isAnyChildVisible;
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
// Draw all highlights
if (_highlights != null)
{
var style = Style.Current;
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
Render2D.FillRectangle(_highlights[i], color);
}
}
/// <inheritdoc />
public override void OnDestroy()
{
// Delete folder item
_folder.Dispose();
base.OnDestroy();
}
private DragDropEffect GetDragEffect(DragData data)
{
if (data is DragDataFiles)
{
if (_folder.CanHaveAssets)
return DragDropEffect.Copy;
}
else
{
if (_dragOverItems.HasValidDrag)
return DragDropEffect.Move;
}
return DragDropEffect.None;
}
private bool ValidateDragItem(ContentItem item)
{
// Reject itself and any parent
return item != _folder && !item.Find(_folder);
}
/// <inheritdoc />
protected override DragDropEffect OnDragEnterHeader(DragData data)
{
if (_dragOverItems == null)
_dragOverItems = new DragItems(ValidateDragItem);
_dragOverItems.OnDragEnter(data);
return GetDragEffect(data);
}
/// <inheritdoc />
protected override DragDropEffect OnDragMoveHeader(DragData data)
{
return GetDragEffect(data);
}
/// <inheritdoc />
protected override void OnDragLeaveHeader()
{
_dragOverItems.OnDragLeave();
base.OnDragLeaveHeader();
}
/// <inheritdoc />
protected override DragDropEffect OnDragDropHeader(DragData data)
{
var result = DragDropEffect.None;
// Check if drop element or files
if (data is DragDataFiles files)
{
// Import files
Editor.Instance.ContentImporting.Import(files.Files, _folder);
result = DragDropEffect.Copy;
Expand();
}
else if (_dragOverItems.HasValidDrag)
{
// Move items
Editor.Instance.ContentDatabase.Move(_dragOverItems.Objects, _folder);
result = DragDropEffect.Move;
Expand();
}
_dragOverItems.OnDragDrop();
return result;
}
/// <inheritdoc />
protected override void DoDragDrop()
{
DoDragDrop(DragItems.GetDragData(_folder));
}
/// <inheritdoc />
protected override void OnLongPress()
{
Select();
StartRenaming();
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (IsFocused)
{
switch (key)
{
case KeyboardKeys.F2:
StartRenaming();
return true;
case KeyboardKeys.Delete:
if (Folder.Exists && CanDelete)
Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
{
switch (key)
{
case KeyboardKeys.D:
if (Folder.Exists && CanDuplicate)
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
}
return base.OnKeyDown(key);
}
}
}

View File

@@ -7,8 +7,8 @@ namespace FlaxEditor.Content
/// <summary> /// <summary>
/// Content tree node used for main directories. /// Content tree node used for main directories.
/// </summary> /// </summary>
/// <seealso cref="ContentFolderTreeNode" /> /// <seealso cref="FlaxEditor.Content.ContentTreeNode" />
public class MainContentFolderTreeNode : ContentFolderTreeNode public class MainContentTreeNode : ContentTreeNode
{ {
private FileSystemWatcher _watcher; private FileSystemWatcher _watcher;
@@ -19,12 +19,12 @@ namespace FlaxEditor.Content
public override bool CanDuplicate => false; public override bool CanDuplicate => false;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MainContentFolderTreeNode"/> class. /// Initializes a new instance of the <see cref="MainContentTreeNode"/> class.
/// </summary> /// </summary>
/// <param name="parent">The parent project.</param> /// <param name="parent">The parent project.</param>
/// <param name="type">The folder type.</param> /// <param name="type">The folder type.</param>
/// <param name="path">The folder path.</param> /// <param name="path">The folder path.</param>
public MainContentFolderTreeNode(ProjectFolderTreeNode parent, ContentFolderType type, string path) public MainContentTreeNode(ProjectTreeNode parent, ContentFolderType type, string path)
: base(parent, type, path) : base(parent, type, path)
{ {
_watcher = new FileSystemWatcher(path) _watcher = new FileSystemWatcher(path)

View File

@@ -1,6 +1,5 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System;
using FlaxEngine.GUI; using FlaxEngine.GUI;
namespace FlaxEditor.Content namespace FlaxEditor.Content
@@ -8,8 +7,8 @@ namespace FlaxEditor.Content
/// <summary> /// <summary>
/// Root tree node for the project workspace. /// Root tree node for the project workspace.
/// </summary> /// </summary>
/// <seealso cref="ContentFolderTreeNode" /> /// <seealso cref="FlaxEditor.Content.ContentTreeNode" />
public sealed class ProjectFolderTreeNode : ContentFolderTreeNode public sealed class ProjectTreeNode : ContentTreeNode
{ {
/// <summary> /// <summary>
/// The project/ /// The project/
@@ -19,18 +18,18 @@ namespace FlaxEditor.Content
/// <summary> /// <summary>
/// The project content directory. /// The project content directory.
/// </summary> /// </summary>
public MainContentFolderTreeNode Content; public MainContentTreeNode Content;
/// <summary> /// <summary>
/// The project source code directory. /// The project source code directory.
/// </summary> /// </summary>
public MainContentFolderTreeNode Source; public MainContentTreeNode Source;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProjectFolderTreeNode"/> class. /// Initializes a new instance of the <see cref="ProjectTreeNode"/> class.
/// </summary> /// </summary>
/// <param name="project">The project.</param> /// <param name="project">The project.</param>
public ProjectFolderTreeNode(ProjectInfo project) public ProjectTreeNode(ProjectInfo project)
: base(null, project.ProjectFolderPath) : base(null, project.ProjectFolderPath)
{ {
Project = project; Project = project;
@@ -49,29 +48,9 @@ namespace FlaxEditor.Content
/// <inheritdoc /> /// <inheritdoc />
public override int Compare(Control other) public override int Compare(Control other)
{ {
if (other is ProjectFolderTreeNode otherProject) // Move the main game project to the top
{ if (Project.Name == Editor.Instance.GameProject.Name)
var gameProject = Editor.Instance.GameProject; return -1;
var engineProject = Editor.Instance.EngineProject;
bool isGame = Project == gameProject;
bool isEngine = Project == engineProject;
bool otherIsGame = otherProject.Project == gameProject;
bool otherIsEngine = otherProject.Project == engineProject;
// Main game project at the top
if (isGame && !otherIsGame)
return -1;
if (!isGame && otherIsGame)
return 1;
// Engine project at the bottom (when distinct)
if (isEngine && !otherIsEngine)
return 1;
if (!isEngine && otherIsEngine)
return -1;
return string.CompareOrdinal(Project.Name, otherProject.Project.Name);
}
return base.Compare(other); return base.Compare(other);
} }
} }

View File

@@ -5,13 +5,13 @@ namespace FlaxEditor.Content
/// <summary> /// <summary>
/// Root tree node for the content workspace. /// Root tree node for the content workspace.
/// </summary> /// </summary>
/// <seealso cref="ContentFolderTreeNode" /> /// <seealso cref="FlaxEditor.Content.ContentTreeNode" />
public sealed class RootContentFolderTreeNode : ContentFolderTreeNode public sealed class RootContentTreeNode : ContentTreeNode
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RootContentFolderTreeNode"/> class. /// Initializes a new instance of the <see cref="RootContentTreeNode"/> class.
/// </summary> /// </summary>
public RootContentFolderTreeNode() public RootContentTreeNode()
: base(null, string.Empty) : base(null, string.Empty)
{ {
} }

View File

@@ -535,8 +535,7 @@ bool GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
{ {
Function<int32()> f; Function<int32()> f;
f.Bind(ThreadFunction); f.Bind(ThreadFunction);
uint32 stackSize = 4 * 1024 * 1024; // Larger stack const auto thread = ThreadSpawner::Start(f, GameCookerServiceInstance.Name, ThreadPriority::Highest);
const auto thread = ThreadSpawner::Start(f, GameCookerServiceInstance.Name, ThreadPriority::Highest, stackSize);
if (thread == nullptr) if (thread == nullptr)
{ {
GameCookerImpl::IsRunning = false; GameCookerImpl::IsRunning = false;

View File

@@ -49,7 +49,7 @@ ArchitectureType WebPlatformTools::GetArchitecture() const
DotNetAOTModes WebPlatformTools::UseAOT() const DotNetAOTModes WebPlatformTools::UseAOT() const
{ {
return DotNetAOTModes::NoDotnet; return DotNetAOTModes::MonoAOTDynamic;//MonoAOTStatic;// DotNetAOTModes::None;//DotNetAOTModes::MonoAOTStatic;//DotNetAOTModes::NoDotnet;
} }
PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format) PixelFormat WebPlatformTools::GetTextureFormat(CookingData& data, TextureBase* texture, PixelFormat format)
@@ -166,8 +166,9 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
// Move .wasm assemblies into the data files in order for dlopen to work (blocking) // Move .wasm assemblies into the data files in order for dlopen to work (blocking)
{ {
Array<String> files; Array<String> files, files2;
FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.wasm"), DirectorySearchOption::AllDirectories); FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.wasm"), DirectorySearchOption::AllDirectories);
FileSystem::DirectoryGetFiles(files, data.OriginalOutputPath, TEXT("*.so"), DirectorySearchOption::AllDirectories);
StringView gameWasm = StringUtils::GetFileNameWithoutExtension(gameJs); StringView gameWasm = StringUtils::GetFileNameWithoutExtension(gameJs);
for (const String& file : files) for (const String& file : files)
{ {
@@ -175,6 +176,12 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
continue; // Skip the main game module continue; // Skip the main game module
FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true); FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true);
} }
for (const String& file : files2)
{
if (StringUtils::GetFileNameWithoutExtension(file) == gameWasm)
continue; // Skip the main game module
FileSystem::MoveFile(data.DataOutputPath / StringUtils::GetFileName(file), file, true);
}
} }
// Pack data files into a single file using Emscripten's file_packager tool // Pack data files into a single file using Emscripten's file_packager tool
@@ -205,15 +212,7 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
FileSystem::CopyFile(dstIcon, platformDataPath / TEXT("favicon.ico")); FileSystem::CopyFile(dstIcon, platformDataPath / TEXT("favicon.ico"));
} }
// Copy custom HTMl template // TODO: customizable HTML templates
auto customHtml = platformSettings->CustomHtml.TrimTrailing();
if (customHtml.HasChars())
{
FileSystem::CopyFile(data.OriginalOutputPath / TEXT("FlaxGame.html"), customHtml);
}
// Rename game website main HTML file to match the most common name used by web servers (index.html)
FileSystem::MoveFile(data.OriginalOutputPath / TEXT("index.html"), data.OriginalOutputPath / TEXT("FlaxGame.html"), true);
// Insert packaged file system with game data // Insert packaged file system with game data
{ {
@@ -262,6 +261,8 @@ bool WebPlatformTools::OnPostProcess(CookingData& data)
return false; return false;
GameCooker::PackageFiles(); GameCooker::PackageFiles();
// TODO: minify/compress output JS files (in Release builds)
LOG(Info, "Output website size: {0} MB", FileSystem::GetDirectorySize(data.OriginalOutputPath) / 1024 / 1024); LOG(Info, "Output website size: {0} MB", FileSystem::GetDirectorySize(data.OriginalOutputPath) / 1024 / 1024);
return false; return false;

View File

@@ -37,8 +37,8 @@ void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
if (cachedData != aotModeCacheValue) if (cachedData != aotModeCacheValue)
{ {
LOG(Info, "AOT cache invalidation"); LOG(Info, "AOT cache invalidation");
FileSystem::DeleteDirectory(data.ManagedCodeOutputPath); // Remove AOT cache //FileSystem::DeleteDirectory(data.ManagedCodeOutputPath); // Remove AOT cache
FileSystem::DeleteDirectory(data.DataOutputPath / TEXT("Dotnet")); // Remove deployed Dotnet libs (be sure to remove any leftovers from previous build) //FileSystem::DeleteDirectory(data.DataOutputPath / TEXT("Dotnet")); // Remove deployed Dotnet libs (be sure to remove any leftovers from previous build)
} }
} }
if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath)) if (!FileSystem::DirectoryExists(data.ManagedCodeOutputPath))

View File

@@ -52,7 +52,6 @@ namespace FlaxEditor.CustomEditors
private readonly List<CustomEditor> _children = new List<CustomEditor>(); private readonly List<CustomEditor> _children = new List<CustomEditor>();
private ValueContainer _values; private ValueContainer _values;
private bool _isSetBlocked; private bool _isSetBlocked;
private bool _isRebuilding;
private bool _skipChildrenRefresh; private bool _skipChildrenRefresh;
private bool _hasValueDirty; private bool _hasValueDirty;
private bool _rebuildOnRefresh; private bool _rebuildOnRefresh;
@@ -179,7 +178,7 @@ namespace FlaxEditor.CustomEditors
public void RebuildLayout() public void RebuildLayout()
{ {
// Skip rebuilding during init // Skip rebuilding during init
if (CurrentCustomEditor == this || _isRebuilding) if (CurrentCustomEditor == this)
return; return;
// Special case for root objects to run normal layout build // Special case for root objects to run normal layout build
@@ -198,7 +197,6 @@ namespace FlaxEditor.CustomEditors
_parent?.RebuildLayout(); _parent?.RebuildLayout();
return; return;
} }
_isRebuilding = true;
var control = layout.ContainerControl; var control = layout.ContainerControl;
var parent = _parent; var parent = _parent;
var parentScrollV = (_presenter?.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1; var parentScrollV = (_presenter?.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1;
@@ -218,7 +216,6 @@ namespace FlaxEditor.CustomEditors
// Restore scroll value // Restore scroll value
if (parentScrollV > -1 && _presenter != null && _presenter.Panel.Parent is Panel panel && panel.VScrollBar != null) if (parentScrollV > -1 && _presenter != null && _presenter.Panel.Parent is Panel panel && panel.VScrollBar != null)
panel.VScrollBar.Value = parentScrollV; panel.VScrollBar.Value = parentScrollV;
_isRebuilding = false;
} }
/// <summary> /// <summary>

View File

@@ -55,8 +55,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
{ {
// TODO: consider editing more than one instance of the same prefab asset at once // TODO: consider editing more than one instance of the same prefab asset at once
var prefab = FlaxEngine.Content.Load<Prefab>(actor.PrefabID); var prefab = FlaxEngine.Content.LoadAsync<Prefab>(actor.PrefabID);
if (prefab) // TODO: don't stall here?
if (prefab && !prefab.WaitForLoaded())
{ {
var prefabObjectId = actor.PrefabObjectID; var prefabObjectId = actor.PrefabObjectID;
var prefabInstance = prefab.GetDefaultInstance(ref prefabObjectId); var prefabInstance = prefab.GetDefaultInstance(ref prefabObjectId);
@@ -202,7 +203,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
//Presenter.BuildLayoutOnUpdate(); //Presenter.BuildLayoutOnUpdate();
// Better way is to just update the reference value using the new default instance of the prefab, created after changes apply // Better way is to just update the reference value using the new default instance of the prefab, created after changes apply
if (Values != null && (Actor)Values[0] && prefab && !prefab.WaitForLoaded()) if (Values != null && prefab && !prefab.WaitForLoaded())
{ {
var actor = (Actor)Values[0]; var actor = (Actor)Values[0];
var prefabObjectId = actor.PrefabObjectID; var prefabObjectId = actor.PrefabObjectID;

View File

@@ -370,7 +370,7 @@ namespace FlaxEditor.CustomEditors.Editors
SetValue(Editor.Instance.ContentDatabase.Find(Utilities.Utils.ToPathAbsolute(path))); SetValue(Editor.Instance.ContentDatabase.Find(Utilities.Utils.ToPathAbsolute(path)));
else if (value is Asset) else if (value is Asset)
SetValue(FlaxEngine.Content.LoadAsync(path)); SetValue(FlaxEngine.Content.LoadAsync(path));
else if (value is string || Values.Type == typeof(string)) else if (value is string)
SetValue(path); SetValue(path);
} }

View File

@@ -61,7 +61,6 @@ public class Editor : EditorModule
options.PrivateDependencies.Add("Renderer"); options.PrivateDependencies.Add("Renderer");
options.PrivateDependencies.Add("TextureTool"); options.PrivateDependencies.Add("TextureTool");
options.PrivateDependencies.Add("Particles"); options.PrivateDependencies.Add("Particles");
options.PrivateDependencies.Add("Terrain");
var platformToolsRoot = Path.Combine(FolderPath, "Cooker", "Platform"); var platformToolsRoot = Path.Combine(FolderPath, "Cooker", "Platform");
var platformToolsRootExternal = Path.Combine(Globals.EngineRoot, "Source", "Platforms"); var platformToolsRootExternal = Path.Combine(Globals.EngineRoot, "Source", "Platforms");

View File

@@ -654,7 +654,7 @@ Window* Editor::CreateMainWindow()
PROFILE_MEM(Editor); PROFILE_MEM(Editor);
Window* window = Managed->GetMainWindow(); Window* window = Managed->GetMainWindow();
#if PLATFORM_LINUX || PLATFORM_MAC #if PLATFORM_LINUX
// Set window icon // Set window icon
const String iconPath = Globals::BinariesFolder / TEXT("Logo.png"); const String iconPath = Globals::BinariesFolder / TEXT("Logo.png");
if (FileSystem::FileExists(iconPath)) if (FileSystem::FileExists(iconPath))

View File

@@ -69,11 +69,6 @@ namespace FlaxEditor
/// </summary> /// </summary>
public static string WindowIcon = "Editor/EditorIcon"; public static string WindowIcon = "Editor/EditorIcon";
/// <summary>
/// The material used for the HS color wheel.
/// </summary>
public static string HSWheelMaterial = "Editor/HSWheel";
/// <summary> /// <summary>
/// The window icons font. /// The window icons font.
/// </summary> /// </summary>

View File

@@ -1,11 +1,10 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.GUI.Input; using FlaxEditor.GUI.Input;
using FlaxEditor.GUI.Tabs;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json; using FlaxEngine.Json;
using System.Collections.Generic;
namespace FlaxEditor.GUI.Dialogs namespace FlaxEditor.GUI.Dialogs
{ {
@@ -26,16 +25,15 @@ namespace FlaxEditor.GUI.Dialogs
/// <seealso cref="FlaxEditor.GUI.Dialogs.Dialog" /> /// <seealso cref="FlaxEditor.GUI.Dialogs.Dialog" />
public class ColorPickerDialog : Dialog, IColorPickerDialog public class ColorPickerDialog : Dialog, IColorPickerDialog
{ {
private const float ButtonsWidth = 60.0f;
private const float PickerMargin = 6.0f; private const float PickerMargin = 6.0f;
private const float EyedropperMargin = 8.0f;
private const float RGBAMargin = 12.0f;
private const float HSVMargin = 0.0f;
private const float ChannelsMargin = 4.0f; private const float ChannelsMargin = 4.0f;
private const float ChannelTextWidth = 12.0f; private const float ChannelTextWidth = 12.0f;
private const float SavedColorButtonWidth = 20.0f; private const float SavedColorButtonWidth = 20.0f;
private const float SavedColorButtonHeight = 20.0f; private const float SavedColorButtonHeight = 20.0f;
private const float TabHeight = 20;
private const float ValueBoxesWidth = 100.0f;
private const float HSVRGBTextWidth = 15.0f;
private const float ColorPreviewHeight = 50.0f;
private const int SavedColorsAmount = 10;
private Color _initialValue; private Color _initialValue;
private Color _value; private Color _value;
@@ -48,19 +46,16 @@ namespace FlaxEditor.GUI.Dialogs
private ColorValueBox.ColorPickerClosedEvent _onClosed; private ColorValueBox.ColorPickerClosedEvent _onClosed;
private ColorSelectorWithSliders _cSelector; private ColorSelectorWithSliders _cSelector;
private Tabs.Tabs _hsvRGBTabs;
private Tab _RGBTab;
private Panel _rgbPanel;
private FloatValueBox _cRed; private FloatValueBox _cRed;
private FloatValueBox _cGreen; private FloatValueBox _cGreen;
private FloatValueBox _cBlue; private FloatValueBox _cBlue;
private Tab _hsvTab; private FloatValueBox _cAlpha;
private Panel _hsvPanel;
private FloatValueBox _cHue; private FloatValueBox _cHue;
private FloatValueBox _cSaturation; private FloatValueBox _cSaturation;
private FloatValueBox _cValue; private FloatValueBox _cValue;
private TextBox _cHex; private TextBox _cHex;
private FloatValueBox _cAlpha; private Button _cCancel;
private Button _cOK;
private Button _cEyedropper; private Button _cEyedropper;
private Button _cLinearSRGB; private Button _cLinearSRGB;
@@ -132,110 +127,97 @@ namespace FlaxEditor.GUI.Dialogs
_savedColors = JsonSerializer.Deserialize<List<Color>>(savedColors); _savedColors = JsonSerializer.Deserialize<List<Color>>(savedColors);
// Selector // Selector
_cSelector = new ColorSelectorWithSliders(180, 21) _cSelector = new ColorSelectorWithSliders(180, 18)
{ {
Location = new Float2(PickerMargin, PickerMargin), Location = new Float2(PickerMargin, PickerMargin),
Parent = this Parent = this
}; };
_cSelector.ColorChanged += x => SelectedColor = x; _cSelector.ColorChanged += x => SelectedColor = x;
_hsvRGBTabs = new Tabs.Tabs
{
Location = new Float2(_cSelector.Right + 30.0f, PickerMargin),
TabsTextHorizontalAlignment = TextAlignment.Center,
Width = ValueBoxesWidth + HSVRGBTextWidth * 2.0f + ChannelsMargin * 2.0f,
Height = (FloatValueBox.DefaultHeight + ChannelsMargin) * 4 + ChannelsMargin,
Parent = this,
};
_hsvRGBTabs.TabsSize = new Float2(_hsvRGBTabs.Width * 0.5f, TabHeight);
_hsvRGBTabs.SelectedTabChanged += SelectedTabChanged;
// RGB Tab
_RGBTab = _hsvRGBTabs.AddTab(new Tab("RGB"));
_rgbPanel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = _RGBTab,
};
// HSV Tab
_hsvTab = _hsvRGBTabs.AddTab(new Tab("HSV"));
_hsvPanel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = _hsvTab,
};
// Red // Red
_cRed = new FloatValueBox(0, HSVRGBTextWidth + ChannelsMargin, PickerMargin, ValueBoxesWidth, 0, float.MaxValue, 0.001f) _cRed = new FloatValueBox(0, _cSelector.Right + PickerMargin + RGBAMargin + ChannelTextWidth, PickerMargin, 100, 0, float.MaxValue, 0.001f)
{ {
Parent = _rgbPanel, Parent = this
}; };
_cRed.ValueChanged += OnRGBAChanged; _cRed.ValueChanged += OnRGBAChanged;
// Green // Green
_cGreen = new FloatValueBox(0, _cRed.X, _cRed.Bottom + ChannelsMargin, _cRed.Width, 0, float.MaxValue, 0.001f) _cGreen = new FloatValueBox(0, _cRed.X, _cRed.Bottom + ChannelsMargin, _cRed.Width, 0, float.MaxValue, 0.001f)
{ {
Parent = _rgbPanel, Parent = this
}; };
_cGreen.ValueChanged += OnRGBAChanged; _cGreen.ValueChanged += OnRGBAChanged;
// Blue // Blue
_cBlue = new FloatValueBox(0, _cRed.X, _cGreen.Bottom + ChannelsMargin, _cRed.Width, 0, float.MaxValue, 0.001f) _cBlue = new FloatValueBox(0, _cRed.X, _cGreen.Bottom + ChannelsMargin, _cRed.Width, 0, float.MaxValue, 0.001f)
{ {
Parent = _rgbPanel, Parent = this
}; };
_cBlue.ValueChanged += OnRGBAChanged; _cBlue.ValueChanged += OnRGBAChanged;
// Hue // Alpha
_cHue = new FloatValueBox(0, HSVRGBTextWidth + ChannelsMargin, PickerMargin, ValueBoxesWidth) _cAlpha = new FloatValueBox(0, _cRed.X, _cBlue.Bottom + ChannelsMargin, _cRed.Width, 0, float.MaxValue, 0.001f)
{ {
Parent = _hsvPanel, Parent = this
Category = Utils.ValueCategory.Angle, };
_cAlpha.ValueChanged += OnRGBAChanged;
// Hue
_cHue = new FloatValueBox(0, PickerMargin + HSVMargin + ChannelTextWidth, _cSelector.Bottom + PickerMargin, 100, 0, 360)
{
Parent = this
}; };
_cHue.ValueChanged += OnHSVChanged; _cHue.ValueChanged += OnHSVChanged;
// Saturation // Saturation
_cSaturation = new FloatValueBox(0, _cHue.X, _cHue.Bottom + ChannelsMargin, _cHue.Width, 0, 100.0f, 0.1f) _cSaturation = new FloatValueBox(0, _cHue.X, _cHue.Bottom + ChannelsMargin, _cHue.Width, 0, 100.0f, 0.1f)
{ {
Parent = _hsvPanel, Parent = this
}; };
_cSaturation.ValueChanged += OnHSVChanged; _cSaturation.ValueChanged += OnHSVChanged;
// Value // Value
_cValue = new FloatValueBox(0, _cHue.X, _cSaturation.Bottom + ChannelsMargin, _cHue.Width, 0, float.MaxValue, 0.1f) _cValue = new FloatValueBox(0, _cHue.X, _cSaturation.Bottom + ChannelsMargin, _cHue.Width, 0, float.MaxValue, 0.1f)
{ {
Parent = _hsvPanel, Parent = this
}; };
_cValue.ValueChanged += OnHSVChanged; _cValue.ValueChanged += OnHSVChanged;
// Alpha // Set valid dialog size based on UI content
_cAlpha = new FloatValueBox(0, _hsvRGBTabs.Left + HSVRGBTextWidth + ChannelsMargin, _hsvRGBTabs.Bottom + ChannelsMargin * 4.0f, ValueBoxesWidth, 0, float.MaxValue, 0.001f) _dialogSize = Size = new Float2(_cRed.Right + PickerMargin, 300);
{
Parent = this,
};
_cAlpha.ValueChanged += OnRGBAChanged;
// Hex // Hex
_cHex = new TextBox(false, _hsvRGBTabs.Left + HSVRGBTextWidth + ChannelsMargin, _cAlpha.Bottom + ChannelsMargin * 2.0f, ValueBoxesWidth) const float hexTextBoxWidth = 80;
_cHex = new TextBox(false, Width - hexTextBoxWidth - PickerMargin, _cSelector.Bottom + PickerMargin, hexTextBoxWidth)
{ {
Parent = this, Parent = this
}; };
_cHex.EditEnd += OnHexChanged; _cHex.EditEnd += OnHexChanged;
// Set valid dialog size based on UI content // Cancel
_dialogSize = Size = new Float2(_hsvRGBTabs.Right + PickerMargin, _cHex.Bottom + 40.0f + ColorPreviewHeight + PickerMargin); _cCancel = new Button(Width - ButtonsWidth - PickerMargin, Height - Button.DefaultHeight - PickerMargin, ButtonsWidth)
{
Text = "Cancel",
Parent = this
};
_cCancel.Clicked += OnCancel;
// OK
_cOK = new Button(_cCancel.Left - ButtonsWidth - PickerMargin, _cCancel.Y, ButtonsWidth)
{
Text = "Ok",
Parent = this
};
_cOK.Clicked += OnSubmit;
// Create saved color buttons // Create saved color buttons
CreateAllSavedColorsButtons(); CreateAllSaveButtons();
// Eyedropper button // Eyedropper button
var style = Style.Current; var style = Style.Current;
_cEyedropper = new Button(_cSelector.BottomLeft.X, _cSelector.BottomLeft.Y - 25.0f, 25.0f, 25.0f) _cEyedropper = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin)
{ {
TooltipText = "Eyedropper tool to pick a color directly from the screen.", TooltipText = "Eyedropper tool to pick a color directly from the screen",
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Search32), BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Search32),
BackgroundColor = style.Foreground, BackgroundColor = style.Foreground,
BackgroundColorHighlighted = style.Foreground.RGBMultiplied(0.9f), BackgroundColorHighlighted = style.Foreground.RGBMultiplied(0.9f),
@@ -244,11 +226,14 @@ namespace FlaxEditor.GUI.Dialogs
Parent = this, Parent = this,
}; };
_cEyedropper.Clicked += OnEyedropStart; _cEyedropper.Clicked += OnEyedropStart;
_cEyedropper.Height = (_cValue.Bottom - _cEyedropper.Y) * 0.5f;
_cEyedropper.Width = _cEyedropper.Height;
_cEyedropper.X -= _cEyedropper.Width;
// Linear/sRGB toggle button // Linear/sRGB toggle button
_cLinearSRGB = new Button(_cSelector.X, _cHex.Bottom + PickerMargin) _cLinearSRGB = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin)
{ {
TooltipText = "Toggles between color preview in Linear and sRGB.", TooltipText = "Toggles between color preview in Linear and sRGB",
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.SplineAligned64), BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.SplineAligned64),
BackgroundColor = _cEyedropper.BackgroundColor, BackgroundColor = _cEyedropper.BackgroundColor,
BackgroundColorHighlighted = _cEyedropper.BackgroundColorHighlighted, BackgroundColorHighlighted = _cEyedropper.BackgroundColorHighlighted,
@@ -276,10 +261,12 @@ namespace FlaxEditor.GUI.Dialogs
foreach (var color in _savedColors) foreach (var color in _savedColors)
{ {
if (color == _value) if (color == _value)
{
return; return;
}
} }
// Set color of button to current value // Set color of button to current value;
button.BackgroundColor = _value; button.BackgroundColor = _value;
button.BackgroundColorHighlighted = _value; button.BackgroundColorHighlighted = _value;
button.BackgroundColorSelected = _value.RGBMultiplied(0.8f); button.BackgroundColorSelected = _value.RGBMultiplied(0.8f);
@@ -291,10 +278,10 @@ namespace FlaxEditor.GUI.Dialogs
var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>)); var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>));
Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors); Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors);
// Create new + button // create new + button
if (_savedColorButtons.Count < SavedColorsAmount) if (_savedColorButtons.Count < 8)
{ {
var savedColorButton = new Button(PickerMargin * (_savedColorButtons.Count + 1) + SavedColorButtonWidth * _savedColorButtons.Count, _cHex.Bottom + 40.0f + ColorPreviewHeight * 0.5f, SavedColorButtonWidth, SavedColorButtonHeight) var savedColorButton = new Button(PickerMargin * (_savedColorButtons.Count + 1) + SavedColorButtonWidth * _savedColorButtons.Count, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
{ {
Text = "+", Text = "+",
Parent = this, Parent = this,
@@ -311,32 +298,11 @@ namespace FlaxEditor.GUI.Dialogs
} }
} }
private void SelectedTabChanged(Tabs.Tabs tabs)
{
if (_rgbPanel == null || _hsvPanel == null)
return;
switch (tabs.SelectedTabIndex)
{
// RGB
case 0:
_rgbPanel.Visible = true;
_hsvPanel.Visible = false;
break;
// HSV
case 1:
_rgbPanel.Visible = false;
_hsvPanel.Visible = true;
break;
}
}
private void OnColorPicked(Color32 colorPicked) private void OnColorPicked(Color32 colorPicked)
{ {
if (_activeEyedropper) if (_activeEyedropper)
{ {
_activeEyedropper = false; _activeEyedropper = false;
_cEyedropper.BackgroundColor = _cEyedropper.BackgroundColorHighlighted = Style.Current.Foreground;
if (colorPicked != Color.Transparent) if (colorPicked != Color.Transparent)
{ {
Color color = colorPicked; Color color = colorPicked;
@@ -351,7 +317,6 @@ namespace FlaxEditor.GUI.Dialogs
private void OnEyedropStart() private void OnEyedropStart()
{ {
_activeEyedropper = true; _activeEyedropper = true;
_cEyedropper.BackgroundColor = _cEyedropper.BackgroundColorHighlighted = Style.Current.BackgroundHighlighted;
Platform.PickScreenColor(); Platform.PickScreenColor();
Platform.PickScreenColorDone += OnColorPicked; Platform.PickScreenColorDone += OnColorPicked;
} }
@@ -369,7 +334,6 @@ namespace FlaxEditor.GUI.Dialogs
if (_disableEvents) if (_disableEvents)
return; return;
_cHue.Value = Mathf.Wrap(_cHue.Value, 0f, 360f);
SelectedColor = Color.FromHSV(_cHue.Value, _cSaturation.Value / 100.0f, _cValue.Value / 100.0f, _cAlpha.Value); SelectedColor = Color.FromHSV(_cHue.Value, _cSaturation.Value / 100.0f, _cValue.Value / 100.0f, _cAlpha.Value);
} }
@@ -410,76 +374,64 @@ namespace FlaxEditor.GUI.Dialogs
base.Draw(); base.Draw();
switch (_hsvRGBTabs.SelectedTabIndex) // RGBA
{ var rgbaR = new Rectangle(_cRed.Left - ChannelTextWidth, _cRed.Y, 10000, _cRed.Height);
// RGB Render2D.DrawText(style.FontMedium, "R", rgbaR, textColor, TextAlignment.Near, TextAlignment.Center);
case 0: rgbaR.Location.Y = _cGreen.Y;
var rgbRect = new Rectangle(_hsvRGBTabs.Left + PickerMargin, _hsvRGBTabs.Top + TabHeight + PickerMargin, 10000, _cRed.Height); Render2D.DrawText(style.FontMedium, "G", rgbaR, textColor, TextAlignment.Near, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, "R", rgbRect, textColor, TextAlignment.Near, TextAlignment.Center); rgbaR.Location.Y = _cBlue.Y;
rgbRect.Location.Y += _cRed.Height + ChannelsMargin; Render2D.DrawText(style.FontMedium, "B", rgbaR, textColor, TextAlignment.Near, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, "G", rgbRect, textColor, TextAlignment.Near, TextAlignment.Center); rgbaR.Location.Y = _cAlpha.Y;
rgbRect.Location.Y += _cRed.Height + ChannelsMargin; Render2D.DrawText(style.FontMedium, "A", rgbaR, textColor, TextAlignment.Near, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, "B", rgbRect, textColor, TextAlignment.Near, TextAlignment.Center);
break;
// HSV
case 1:
// Left
var hsvLeftRect = new Rectangle(_hsvRGBTabs.Left + PickerMargin, _hsvRGBTabs.Top + TabHeight + PickerMargin, 10000, _cHue.Height);
Render2D.DrawText(style.FontMedium, "H", hsvLeftRect, textColor, TextAlignment.Near, TextAlignment.Center);
hsvLeftRect.Location.Y += _cHue.Height + ChannelsMargin;
Render2D.DrawText(style.FontMedium, "S", hsvLeftRect, textColor, TextAlignment.Near, TextAlignment.Center);
hsvLeftRect.Location.Y += _cHue.Height + ChannelsMargin;
Render2D.DrawText(style.FontMedium, "V", hsvLeftRect, textColor, TextAlignment.Near, TextAlignment.Center);
// Right // HSV left
var hsvRightRect = new Rectangle(_hsvRGBTabs.Right - HSVRGBTextWidth, _hsvRGBTabs.Top + TabHeight + PickerMargin, ChannelTextWidth, _cHue.Height); var hsvHl = new Rectangle(_cHue.Left - ChannelTextWidth, _cHue.Y, 10000, _cHue.Height);
Render2D.DrawText(style.FontMedium, "°", hsvRightRect, textColor, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontMedium, "H", hsvHl, textColor, TextAlignment.Near, TextAlignment.Center);
hsvRightRect.Location.Y += _cHue.Height + ChannelsMargin; hsvHl.Location.Y = _cSaturation.Y;
Render2D.DrawText(style.FontMedium, "%", hsvRightRect, textColor, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontMedium, "S", hsvHl, textColor, TextAlignment.Near, TextAlignment.Center);
hsvRightRect.Location.Y += _cHue.Height + ChannelsMargin; hsvHl.Location.Y = _cValue.Y;
Render2D.DrawText(style.FontMedium, "%", hsvRightRect, textColor, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontMedium, "V", hsvHl, textColor, TextAlignment.Near, TextAlignment.Center);
break;
}
// A // HSV right
var alphaHexRect = new Rectangle(_hsvRGBTabs.Left + PickerMargin, _cAlpha.Top, ChannelTextWidth, _cAlpha.Height); var hsvHr = new Rectangle(_cHue.Right + 2, _cHue.Y, 10000, _cHue.Height);
Render2D.DrawText(style.FontMedium, "A", alphaHexRect, textColor, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontMedium, "°", hsvHr, textColor, TextAlignment.Near, TextAlignment.Center);
hsvHr.Location.Y = _cSaturation.Y;
Render2D.DrawText(style.FontMedium, "%", hsvHr, textColor, TextAlignment.Near, TextAlignment.Center);
hsvHr.Location.Y = _cValue.Y;
Render2D.DrawText(style.FontMedium, "%", hsvHr, textColor, TextAlignment.Near, TextAlignment.Center);
// Hex // Hex
alphaHexRect.Y += _cAlpha.Height + ChannelsMargin * 2.0f; var hex = new Rectangle(_cHex.Left - 26, _cHex.Y, 10000, _cHex.Height);
alphaHexRect.X -= 5.0f; // "Hex" is two characters wider than the other labels so we need to adjust for that Render2D.DrawText(style.FontMedium, "Hex", hex, textColor, TextAlignment.Near, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, "Hex", alphaHexRect, textColor, TextAlignment.Far, TextAlignment.Center);
// Color difference // Color difference
var differenceRect = new Rectangle(_hsvRGBTabs.Left, _cHex.Bottom + 40.0f, _hsvRGBTabs.Width, ColorPreviewHeight); var newRect = new Rectangle(_cOK.X - 3, _cHex.Bottom + PickerMargin, 130, 0);
newRect.Size.Y = 50;
// Draw checkerboard for background of color to help with transparency Render2D.FillRectangle(newRect, Color.White);
Render2D.FillRectangle(differenceRect, Color.White);
var smallRectSize = 10; var smallRectSize = 10;
var numHor = Mathf.CeilToInt(differenceRect.Width / smallRectSize); var numHor = Mathf.FloorToInt(newRect.Width / smallRectSize);
var numVer = Mathf.CeilToInt(differenceRect.Height / smallRectSize); var numVer = Mathf.FloorToInt(newRect.Height / smallRectSize);
Render2D.PushClip(differenceRect); // Draw checkerboard for background of color to help with transparency
for (int i = 0; i < numHor; i++) for (int i = 0; i < numHor; i++)
{ {
for (int j = 0; j < numVer; j++) for (int j = 0; j < numVer; j++)
{ {
if ((i + j) % 2 == 0) if ((i + j) % 2 == 0)
{ {
var rect = new Rectangle(differenceRect.X + smallRectSize * i, differenceRect.Y + smallRectSize * j, new Float2(smallRectSize)); var rect = new Rectangle(newRect.X + smallRectSize * i, newRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.FillRectangle(rect, Color.Gray); Render2D.FillRectangle(rect, Color.Gray);
} }
} }
} }
Render2D.PopClip(); Render2D.FillRectangle(newRect, _linear ? _value.ToSRgb() : _value);
Render2D.FillRectangle(differenceRect, _linear ? _value.ToSRgb() : _value);
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnShow() protected override void OnShow()
{ {
// Apply changes on lost focus // Auto cancel on lost focus
#if !PLATFORM_LINUX #if !PLATFORM_LINUX
((WindowRootControl)Root).Window.LostFocus += OnSubmit; ((WindowRootControl)Root).Window.LostFocus += OnWindowLostFocus;
#endif #endif
base.OnShow(); base.OnShow();
@@ -492,7 +444,6 @@ namespace FlaxEditor.GUI.Dialogs
{ {
// Cancel eye dropping // Cancel eye dropping
_activeEyedropper = false; _activeEyedropper = false;
_cEyedropper.BackgroundColor = _cEyedropper.BackgroundColorHighlighted = Style.Current.Foreground;
Platform.PickScreenColorDone -= OnColorPicked; Platform.PickScreenColorDone -= OnColorPicked;
return true; return true;
} }
@@ -504,7 +455,9 @@ namespace FlaxEditor.GUI.Dialogs
public override bool OnMouseUp(Float2 location, MouseButton button) public override bool OnMouseUp(Float2 location, MouseButton button)
{ {
if (base.OnMouseUp(location, button)) if (base.OnMouseUp(location, button))
{
return true; return true;
}
var child = GetChildAtRecursive(location); var child = GetChildAtRecursive(location);
if (button == MouseButton.Right && child is Button b && b.Tag is Color c) if (button == MouseButton.Right && child is Button b && b.Tag is Color c)
@@ -566,20 +519,20 @@ namespace FlaxEditor.GUI.Dialogs
} }
_savedColorButtons.Clear(); _savedColorButtons.Clear();
CreateAllSavedColorsButtons(); CreateAllSaveButtons();
// Save new colors // Save new colors
var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>)); var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>));
Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors); Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors);
} }
private void CreateAllSavedColorsButtons() private void CreateAllSaveButtons()
{ {
// Create saved color buttons // Create saved color buttons
for (int i = 0; i < _savedColors.Count; i++) for (int i = 0; i < _savedColors.Count; i++)
{ {
var savedColor = _savedColors[i]; var savedColor = _savedColors[i];
var savedColorButton = new Button(PickerMargin * (i + 1) + SavedColorButtonWidth * i, _cHex.Bottom + 40.0f + ColorPreviewHeight * 0.5f, SavedColorButtonWidth, SavedColorButtonHeight) var savedColorButton = new Button(PickerMargin * (i + 1) + SavedColorButtonWidth * i, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
{ {
Parent = this, Parent = this,
Tag = savedColor, Tag = savedColor,
@@ -590,9 +543,9 @@ namespace FlaxEditor.GUI.Dialogs
savedColorButton.ButtonClicked += OnSavedColorButtonClicked; savedColorButton.ButtonClicked += OnSavedColorButtonClicked;
_savedColorButtons.Add(savedColorButton); _savedColorButtons.Add(savedColorButton);
} }
if (_savedColors.Count < SavedColorsAmount) if (_savedColors.Count < 8)
{ {
var savedColorButton = new Button(PickerMargin * (_savedColors.Count + 1) + SavedColorButtonWidth * _savedColors.Count, _cHex.Bottom + 40.0f + ColorPreviewHeight * 0.5f, SavedColorButtonWidth, SavedColorButtonHeight) var savedColorButton = new Button(PickerMargin * (_savedColors.Count + 1) + SavedColorButtonWidth * _savedColors.Count, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
{ {
Text = "+", Text = "+",
Parent = this, Parent = this,
@@ -604,6 +557,19 @@ namespace FlaxEditor.GUI.Dialogs
} }
} }
private void OnWindowLostFocus()
{
// Auto apply color on defocus
var autoAcceptColorPickerChange = Editor.Instance.Options.Options.Interface.AutoAcceptColorPickerChange;
if (_useDynamicEditing && _initialValue != _value && _canPassLastChangeEvent && autoAcceptColorPickerChange)
{
_canPassLastChangeEvent = false;
_onChanged?.Invoke(_value, false);
}
OnCancel();
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnSubmit() public override void OnSubmit()
{ {
@@ -611,9 +577,6 @@ namespace FlaxEditor.GUI.Dialogs
return; return;
_disableEvents = true; _disableEvents = true;
// Ensure the cursor is restored
Cursor = CursorType.Default;
// Send color event if modified // Send color event if modified
if (_value != _initialValue) if (_value != _initialValue)
{ {
@@ -630,9 +593,6 @@ namespace FlaxEditor.GUI.Dialogs
return; return;
_disableEvents = true; _disableEvents = true;
// Ensure the cursor is restored
Cursor = CursorType.Default;
// Restore color if modified // Restore color if modified
if (_useDynamicEditing && _initialValue != _value && _canPassLastChangeEvent) if (_useDynamicEditing && _initialValue != _value && _canPassLastChangeEvent)
{ {

View File

@@ -12,13 +12,6 @@ namespace FlaxEditor.GUI.Dialogs
/// <seealso cref="FlaxEngine.GUI.ContainerControl" /> /// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public class ColorSelector : ContainerControl public class ColorSelector : ContainerControl
{ {
private const String GrayedOutParamName = "GrayedOut";
/// <summary>
/// Offset value applied to mouse cursor position when the user lets go of wheel or sliders.
/// </summary>
protected const float MouseCursorOffset = 6.0f;
/// <summary> /// <summary>
/// The color. /// The color.
/// </summary> /// </summary>
@@ -29,22 +22,9 @@ namespace FlaxEditor.GUI.Dialogs
/// </summary> /// </summary>
protected Rectangle _wheelRect; protected Rectangle _wheelRect;
private readonly MaterialBase _hsWheelMaterial; private readonly SpriteHandle _colorWheelSprite;
private bool _isMouseDownWheel; private bool _isMouseDownWheel;
private Rectangle wheelDragRect
{
get
{
var hsv = _color.ToHSV();
float hAngle = hsv.X * Mathf.DegreesToRadians;
float hRadius = hsv.Y * _wheelRect.Width * 0.5f;
var hsPos = new Float2(hRadius * Mathf.Cos(hAngle), -hRadius * Mathf.Sin(hAngle));
float wheelBoxSize = IsSliding ? 9.0f : 5.0f;
return new Rectangle(hsPos - (wheelBoxSize * 0.5f) + _wheelRect.Center, new Float2(wheelBoxSize));
}
}
/// <summary> /// <summary>
/// Occurs when selected color gets changed. /// Occurs when selected color gets changed.
/// </summary> /// </summary>
@@ -98,8 +78,7 @@ namespace FlaxEditor.GUI.Dialogs
{ {
AutoFocus = true; AutoFocus = true;
_hsWheelMaterial = FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.HSWheelMaterial); _colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
_hsWheelMaterial = _hsWheelMaterial.CreateVirtualInstance();
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize); _wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
} }
@@ -186,19 +165,17 @@ namespace FlaxEditor.GUI.Dialogs
{ {
base.Draw(); base.Draw();
var hsv = _color.ToHSV();
bool enabled = EnabledInHierarchy; bool enabled = EnabledInHierarchy;
_hsWheelMaterial.SetParameterValue(GrayedOutParamName, enabled ? 1.0f : 0.5f);
Render2D.DrawMaterial(_hsWheelMaterial, _wheelRect, enabled ? Color.White : Color.Gray);
// Wheel // Wheel
float boxExpand = (2.0f * 4.0f / 128.0f) * _wheelRect.Width; float boxExpand = (2.0f * 4.0f / 128.0f) * _wheelRect.Width;
Render2D.DrawMaterial(_hsWheelMaterial, _wheelRect, enabled ? Color.White : Color.Gray); Render2D.DrawSprite(_colorWheelSprite, _wheelRect.MakeExpanded(boxExpand), enabled ? Color.White : Color.Gray);
Float3 hsv = _color.ToHSV(); float hAngle = hsv.X * Mathf.DegreesToRadians;
Color hsColor = Color.FromHSV(new Float3(hsv.X, hsv.Y, 1)); float hRadius = hsv.Y * _wheelRect.Width * 0.5f;
Rectangle wheelRect = wheelDragRect; var hsPos = new Float2(hRadius * Mathf.Cos(hAngle), -hRadius * Mathf.Sin(hAngle));
Render2D.FillRectangle(wheelRect, hsColor); const float wheelBoxSize = 4.0f;
Render2D.DrawRectangle(wheelRect, Color.Black, _isMouseDownWheel ? 2.0f : 1.0f); Render2D.DrawRectangle(new Rectangle(hsPos - (wheelBoxSize * 0.5f) + _wheelRect.Center, new Float2(wheelBoxSize)), _isMouseDownWheel ? Color.Gray : Color.Black);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -217,15 +194,6 @@ namespace FlaxEditor.GUI.Dialogs
base.OnMouseMove(location); base.OnMouseMove(location);
} }
/// <inheritdoc />
public override void OnMouseMoveRelative(Float2 motion)
{
var location = PointFromScreen(FlaxEngine.Input.MouseScreenPosition);
UpdateMouse(ref location);
base.OnMouseMoveRelative(motion);
}
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button) public override bool OnMouseDown(Float2 location, MouseButton button)
{ {
@@ -234,7 +202,6 @@ namespace FlaxEditor.GUI.Dialogs
if (!_isMouseDownWheel) if (!_isMouseDownWheel)
{ {
_isMouseDownWheel = true; _isMouseDownWheel = true;
Cursor = CursorType.Hidden;
StartMouseCapture(); StartMouseCapture();
SlidingStart?.Invoke(); SlidingStart?.Invoke();
} }
@@ -251,10 +218,6 @@ namespace FlaxEditor.GUI.Dialogs
if (button == MouseButton.Left && _isMouseDownWheel) if (button == MouseButton.Left && _isMouseDownWheel)
{ {
EndMouseCapture(); EndMouseCapture();
// Make the cursor appear where the user expects it to be (position of selection rectangle)
Rectangle dragRect = wheelDragRect;
Root.MousePosition = dragRect.Center + MouseCursorOffset;
Cursor = CursorType.Default;
EndSliding(); EndSliding();
return true; return true;
} }
@@ -283,10 +246,10 @@ namespace FlaxEditor.GUI.Dialogs
/// <seealso cref="ColorSelector" /> /// <seealso cref="ColorSelector" />
public class ColorSelectorWithSliders : ColorSelector public class ColorSelectorWithSliders : ColorSelector
{ {
private Rectangle _valueSliderRect; private Rectangle _slider1Rect;
private Rectangle _alphaSliderRect; private Rectangle _slider2Rect;
private bool _isMouseDownValueSlider; private bool _isMouseDownSlider1;
private bool _isMouseDownAlphaSlider; private bool _isMouseDownSlider2;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ColorSelectorWithSliders"/> class. /// Initializes a new instance of the <see cref="ColorSelectorWithSliders"/> class.
@@ -297,26 +260,26 @@ namespace FlaxEditor.GUI.Dialogs
: base(wheelSize) : base(wheelSize)
{ {
// Setup dimensions // Setup dimensions
const float slidersMargin = 10.0f; const float slidersMargin = 8.0f;
_valueSliderRect = new Rectangle(wheelSize + slidersMargin, 0, slidersThickness, wheelSize); _slider1Rect = new Rectangle(wheelSize + slidersMargin, 0, slidersThickness, wheelSize);
_alphaSliderRect = new Rectangle(_valueSliderRect.Right + slidersMargin * 1.5f, _valueSliderRect.Y, slidersThickness, _valueSliderRect.Height); _slider2Rect = new Rectangle(_slider1Rect.Right + slidersMargin, _slider1Rect.Y, slidersThickness, _slider1Rect.Height);
Size = new Float2(_alphaSliderRect.Right, wheelSize); Size = new Float2(_slider2Rect.Right, wheelSize);
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void UpdateMouse(ref Float2 location) protected override void UpdateMouse(ref Float2 location)
{ {
if (_isMouseDownValueSlider) if (_isMouseDownSlider1)
{ {
var hsv = _color.ToHSV(); var hsv = _color.ToHSV();
hsv.Z = 1.0f - Mathf.Saturate((location.Y - _valueSliderRect.Y) / _valueSliderRect.Height); hsv.Z = 1.0f - Mathf.Saturate((location.Y - _slider1Rect.Y) / _slider1Rect.Height);
Color = Color.FromHSV(hsv, _color.A); Color = Color.FromHSV(hsv, _color.A);
} }
else if (_isMouseDownAlphaSlider) else if (_isMouseDownSlider2)
{ {
var color = _color; var color = _color;
color.A = 1.0f - Mathf.Saturate((location.Y - _alphaSliderRect.Y) / _alphaSliderRect.Height); color.A = 1.0f - Mathf.Saturate((location.Y - _slider2Rect.Y) / _slider2Rect.Height);
Color = color; Color = color;
} }
@@ -333,69 +296,56 @@ namespace FlaxEditor.GUI.Dialogs
// Cache data // Cache data
var style = Style.Current; var style = Style.Current;
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
var hsv = _color.ToHSV(); var hsv = _color.ToHSV();
var hs = hsv; var hs = hsv;
hs.Z = 1.0f; hs.Z = 1.0f;
Color hsC = Color.FromHSV(hs); Color hsC = Color.FromHSV(hs);
const float slidersOffset = 3.0f;
const float slidersThickness = 4.0f;
// Value slider // Value
float valueKnobExpand = _isMouseDownValueSlider ? 10.0f : 4.0f; float valueY = _slider2Rect.Height * (1 - hsv.Z);
float valueY = _valueSliderRect.Height * (1 - hsv.Z); var valueR = new Rectangle(_slider1Rect.X - slidersOffset, _slider1Rect.Y + valueY - slidersThickness / 2, _slider1Rect.Width + slidersOffset * 2, slidersThickness);
float valueKnobWidth = _valueSliderRect.Width + valueKnobExpand; Render2D.FillRectangle(_slider1Rect, hsC, hsC, Color.Black, Color.Black);
float valueKnobHeight = _isMouseDownValueSlider ? 7.0f : 4.0f; Render2D.DrawRectangle(_slider1Rect, _isMouseDownSlider1 ? style.BackgroundSelected : Color.Black);
float valueKnobX = _valueSliderRect.X - valueKnobExpand * 0.5f; Render2D.DrawRectangle(valueR, _isMouseDownSlider1 ? Color.White : Color.Gray);
float valueKnobY = _valueSliderRect.Y + valueY - valueKnobHeight * 0.5f;
Rectangle valueKnobRect = new Rectangle(valueKnobX, valueKnobY, valueKnobWidth, valueKnobHeight);
Render2D.FillRectangle(_valueSliderRect, hsC, hsC, Color.Black, Color.Black);
// Draw one black and one white border to make the knob visible at any saturation level
Render2D.DrawRectangle(valueKnobRect, Color.White, _isMouseDownValueSlider ? 3.0f : 2.0f);
Render2D.DrawRectangle(valueKnobRect, Color.Black, _isMouseDownValueSlider ? 2.0f : 1.0f);
// Draw checkerboard pattern as background of alpha slider // Draw checkerboard pattern to part of the alpha slider background
Render2D.FillRectangle(_alphaSliderRect, Color.White); var alphaRect = _slider2Rect;
var smallRectSize = _alphaSliderRect.Width / 2.0f; Render2D.FillRectangle(alphaRect, Color.White);
var numHor = Mathf.CeilToInt(_alphaSliderRect.Width / smallRectSize); var smallRectSize = alphaRect.Width * 0.5f;
var numVer = Mathf.CeilToInt(_alphaSliderRect.Height / smallRectSize); var numHor = Mathf.CeilToInt(alphaRect.Width / smallRectSize);
Render2D.PushClip(_alphaSliderRect); var numVer = Mathf.CeilToInt(alphaRect.Height / smallRectSize);
for (int i = 0; i < numHor; i++) for (int i = 0; i < numHor; i++)
{ {
for (int j = 0; j < numVer; j++) for (int j = 0; j < numVer; j++)
{ {
if ((i + j) % 2 == 0) if ((i + j) % 2 == 0)
{ {
var rect = new Rectangle(_alphaSliderRect.X + smallRectSize * i, _alphaSliderRect.Y + smallRectSize * j, new Float2(smallRectSize)); var rect = new Rectangle(alphaRect.X + smallRectSize * i, alphaRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.PushClip(alphaRect);
Render2D.FillRectangle(rect, Color.Gray); Render2D.FillRectangle(rect, Color.Gray);
Render2D.PopClip();
} }
} }
} }
Render2D.PopClip();
// Alpha slider // Alpha
float alphaKnobExpand = _isMouseDownAlphaSlider ? 10.0f : 4.0f; float alphaY = _slider2Rect.Height * (1 - _color.A);
float alphaY = _alphaSliderRect.Height * (1 - _color.A); var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);
float alphaKnobWidth = _alphaSliderRect.Width + alphaKnobExpand;
float alphaKnobHeight = _isMouseDownAlphaSlider ? 7.0f : 4.0f;
float alphaKnobX = _alphaSliderRect.X - alphaKnobExpand * 0.5f;
float alphaKnobY = _alphaSliderRect.Y + alphaY - alphaKnobExpand * 0.5f;
Rectangle alphaKnobRect = new Rectangle(alphaKnobX, alphaKnobY, alphaKnobWidth, alphaKnobHeight);
var color = _color; var color = _color;
color.A = 1; // Prevent alpha slider fill from becoming transparent color.A = 1; // Keep slider 2 fill rect from changing color alpha while selecting.
Render2D.FillRectangle(_alphaSliderRect, color, color, Color.Transparent, Color.Transparent); Render2D.FillRectangle(_slider2Rect, color, color, Color.Transparent, Color.Transparent);
// Draw one black and one white border to make the knob visible at any saturation level Render2D.DrawRectangle(_slider2Rect, _isMouseDownSlider2 ? style.BackgroundSelected : Color.Black);
Render2D.DrawRectangle(alphaKnobRect, Color.White, _isMouseDownAlphaSlider ? 3.0f : 2.0f); Render2D.DrawRectangle(alphaR, _isMouseDownSlider2 ? Color.White : Color.Gray);
Render2D.DrawRectangle(alphaKnobRect, Color.Black, _isMouseDownAlphaSlider ? 2.0f : 1.0f);
Render2D.Features = features;
} }
/// <inheritdoc /> /// <inheritdoc />
public override void OnLostFocus() public override void OnLostFocus()
{ {
// Clear flags // Clear flags
_isMouseDownValueSlider = false; _isMouseDownSlider1 = false;
_isMouseDownAlphaSlider = false; _isMouseDownSlider2 = false;
base.OnLostFocus(); base.OnLostFocus();
} }
@@ -403,17 +353,15 @@ namespace FlaxEditor.GUI.Dialogs
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button) public override bool OnMouseDown(Float2 location, MouseButton button)
{ {
if (button == MouseButton.Left && _valueSliderRect.Contains(location)) if (button == MouseButton.Left && _slider1Rect.Contains(location))
{ {
_isMouseDownValueSlider = true; _isMouseDownSlider1 = true;
Cursor = CursorType.Hidden;
StartMouseCapture(); StartMouseCapture();
UpdateMouse(ref location); UpdateMouse(ref location);
} }
if (button == MouseButton.Left && _alphaSliderRect.Contains(location)) if (button == MouseButton.Left && _slider2Rect.Contains(location))
{ {
_isMouseDownAlphaSlider = true; _isMouseDownSlider2 = true;
Cursor = CursorType.Hidden;
StartMouseCapture(); StartMouseCapture();
UpdateMouse(ref location); UpdateMouse(ref location);
} }
@@ -424,16 +372,10 @@ namespace FlaxEditor.GUI.Dialogs
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button) public override bool OnMouseUp(Float2 location, MouseButton button)
{ {
if (button == MouseButton.Left && (_isMouseDownValueSlider || _isMouseDownAlphaSlider)) if (button == MouseButton.Left && (_isMouseDownSlider1 || _isMouseDownSlider2))
{ {
// Make the cursor appear where the user expects it to be (center of slider horizontally and slider knob position vertically) _isMouseDownSlider1 = false;
float sliderCenter = _isMouseDownValueSlider ? _valueSliderRect.Center.X : _alphaSliderRect.Center.X; _isMouseDownSlider2 = false;
// Calculate y position based on the slider knob to avoid incrementing value by a small amount when the user repeatedly clicks the slider (f.e. when moving in small steps)
float mouseSliderPosition = _isMouseDownValueSlider ? _valueSliderRect.Y + _valueSliderRect.Height * (1 - _color.ToHSV().Z) + MouseCursorOffset : _alphaSliderRect.Y + _alphaSliderRect.Height * (1 - _color.A) + MouseCursorOffset;
Root.MousePosition = new Float2(sliderCenter + MouseCursorOffset, Mathf.Clamp(mouseSliderPosition, _valueSliderRect.Top, _valueSliderRect.Bottom));
Cursor = CursorType.Default;
_isMouseDownValueSlider = false;
_isMouseDownAlphaSlider = false;
EndMouseCapture(); EndMouseCapture();
return true; return true;
} }
@@ -445,8 +387,8 @@ namespace FlaxEditor.GUI.Dialogs
public override void OnEndMouseCapture() public override void OnEndMouseCapture()
{ {
// Clear flags // Clear flags
_isMouseDownValueSlider = false; _isMouseDownSlider1 = false;
_isMouseDownAlphaSlider = false; _isMouseDownSlider2 = false;
base.OnEndMouseCapture(); base.OnEndMouseCapture();
} }

View File

@@ -135,7 +135,11 @@ namespace FlaxEditor.GUI.Docking
settings.MaximumSize = Float2.Zero; // Unlimited size settings.MaximumSize = Float2.Zero; // Unlimited size
settings.Fullscreen = false; settings.Fullscreen = false;
settings.HasBorder = true; settings.HasBorder = true;
#if PLATFORM_SDL
settings.SupportsTransparency = true; settings.SupportsTransparency = true;
#else
settings.SupportsTransparency = false;
#endif
settings.ActivateWhenFirstShown = true; settings.ActivateWhenFirstShown = true;
settings.AllowInput = true; settings.AllowInput = true;
settings.AllowMinimize = true; settings.AllowMinimize = true;
@@ -207,7 +211,6 @@ namespace FlaxEditor.GUI.Docking
{ {
if (ChildPanelsCount > 0) if (ChildPanelsCount > 0)
return; return;
// Close window // Close window
_window?.Close(); _window?.Close();
} }

View File

@@ -269,9 +269,8 @@ namespace FlaxEditor.GUI.Docking
if (_toDock == null) if (_toDock == null)
return; return;
var window = _toDock.RootWindow?.Window; if (_toDock.RootWindow.Window != _dragSourceWindow)
if (window != null && window != _dragSourceWindow) _toDock.RootWindow.Window.MouseUp -= OnMouseUp;
window.MouseUp -= OnMouseUp;
_dockHintDown?.Parent.RemoveChild(_dockHintDown); _dockHintDown?.Parent.RemoveChild(_dockHintDown);
_dockHintUp?.Parent.RemoveChild(_dockHintUp); _dockHintUp?.Parent.RemoveChild(_dockHintUp);
@@ -328,10 +327,10 @@ namespace FlaxEditor.GUI.Docking
_toDock?.RootWindow.Window.BringToFront(); _toDock?.RootWindow.Window.BringToFront();
//_toDock?.RootWindow.Window.Focus(); //_toDock?.RootWindow.Window.Focus();
#if PLATFORM_SDL
// Make the dragged window transparent when dock hints are visible // Make the dragged window transparent when dock hints are visible
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity; _toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
#else
#if !PLATFORM_SDL
// Bring the drop source always to the top // Bring the drop source always to the top
if (_dragSourceWindow != null) if (_dragSourceWindow != null)
_dragSourceWindow.BringToFront(); _dragSourceWindow.BringToFront();

View File

@@ -76,23 +76,9 @@ namespace FlaxEditor.GUI
toolstrip.IsLayoutLocked = toolstripLocked; toolstrip.IsLayoutLocked = toolstripLocked;
toolstrip.ItemsMargin = toolstripMargin; toolstrip.ItemsMargin = toolstripMargin;
var margin = toolstrip.ItemsMargin; var lastToolstripButton = toolstrip.LastButton;
float xOffset = margin.Left;
bool hadChild = false;
for (int i = 0; i < toolstrip.ChildrenCount; i++)
{
var child = toolstrip.GetChild(i);
if (child == this || !child.Visible)
continue;
hadChild = true;
xOffset += child.Width + margin.Width;
}
var right = hadChild ? xOffset - margin.Width : margin.Left;
var parentSize = Parent.Size; var parentSize = Parent.Size;
var x = right + 8.0f; Bounds = new Rectangle(lastToolstripButton.Right + 8.0f, 0, parentSize.X - X - 8.0f, toolstrip.Height);
var width = Mathf.Max(parentSize.X - x - 8.0f, 0.0f);
Bounds = new Rectangle(x, 0, width, toolstrip.Height);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.GUI
} }
// Select the first platform // Select the first platform
_selected = platforms[0].PlatformType; _selected = PlatformType.Web;
((Image)Children[0]).Color = _selectedColor; ((Image)Children[0]).Color = _selectedColor;
((Image)Children[0]).MouseOverColor = _selectedColor; ((Image)Children[0]).MouseOverColor = _selectedColor;
} }

View File

@@ -2148,9 +2148,10 @@ namespace FlaxEditor.GUI.Timeline
/// </summary> /// </summary>
public void ShowWholeTimeline() public void ShowWholeTimeline()
{ {
const float padding = 40f; var viewWidth = Width;
Zoom = (_backgroundArea.Width - padding * 2f) / (Duration * UnitsPerSecond); var timelineWidth = Duration * UnitsPerSecond * Zoom + 8 * StartOffset;
_backgroundArea.ViewOffset = new Float2(-_leftEdge.X + padding, _backgroundArea.ViewOffset.Y); _backgroundArea.ViewOffset = Float2.Zero;
Zoom = viewWidth / timelineWidth;
} }
/// <summary> /// <summary>

View File

@@ -1,300 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Options;
using FlaxEditor.Viewport;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Gizmo;
[HideInEditor]
internal class DirectionGizmo : ContainerControl
{
public const float DefaultGizmoSize = 112.5f;
private const float AxisLength = 71.25f;
private const float SpriteRadius = 10.85f;
private IGizmoOwner _owner;
private ViewportProjection _viewportProjection;
private EditorViewport _viewport;
private Vector3 _gizmoCenter;
private float _gizmoBrightness;
private float _gizmoOpacity;
private float _backgroundOpacity;
private float _axisLength;
private float _spriteRadius;
private AxisData _xAxisData;
private AxisData _yAxisData;
private AxisData _zAxisData;
private AxisData _negXAxisData;
private AxisData _negYAxisData;
private AxisData _negZAxisData;
private List<AxisData> _axisData = new List<AxisData>();
private int _hoveredAxisIndex = -1;
private SpriteHandle _posHandle;
private SpriteHandle _negHandle;
private FontReference _fontReference;
// Store sprite positions for hover detection
private List<(Float2 position, AxisDirection direction)> _spritePositions = new List<(Float2, AxisDirection)>();
private struct ViewportProjection
{
private Matrix _viewProjection;
private BoundingFrustum _frustum;
private FlaxEngine.Viewport _viewport;
private Vector3 _origin;
public void Init(EditorViewport editorViewport)
{
// Inline EditorViewport.ProjectPoint to save on calculation for large set of points
_viewport = new FlaxEngine.Viewport(0, 0, editorViewport.Width, editorViewport.Height);
_frustum = editorViewport.ViewFrustum;
_viewProjection = _frustum.Matrix;
_origin = editorViewport.Task.View.Origin;
}
public void ProjectPoint(Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation)
{
worldSpaceLocation -= _origin;
_viewport.Project(ref worldSpaceLocation, ref _viewProjection, out var projected);
viewportSpaceLocation = new Float2((float)projected.X, (float)projected.Y);
}
}
private struct AxisData
{
public Float2 Delta;
public float Distance;
public string Label;
public Color AxisColor;
public bool Negative;
public AxisDirection Direction;
}
private enum AxisDirection
{
PosX,
PosY,
PosZ,
NegX,
NegY,
NegZ
}
/// <summary>
/// Constructor of the Direction Gizmo
/// </summary>
/// <param name="owner">The owner of this object.</param>
public DirectionGizmo(IGizmoOwner owner)
{
_owner = owner;
_viewport = owner.Viewport;
_viewportProjection.Init(owner.Viewport);
_xAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = false, Direction = AxisDirection.PosX };
_yAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = false, Direction = AxisDirection.PosY };
_zAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Z", AxisColor = new Color(0.0f, 0.3607f, 0.9f, 1.0f), Negative = false, Direction = AxisDirection.PosZ };
_negXAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = true, Direction = AxisDirection.NegX };
_negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true, Direction = AxisDirection.NegY };
_negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.3607f, 0.9f, 1.0f), Negative = true, Direction = AxisDirection.NegZ };
_axisData.EnsureCapacity(6);
_spritePositions.EnsureCapacity(6);
var editor = Editor.Instance;
_posHandle = editor.Icons.VisjectBoxClosed32;
_negHandle = editor.Icons.VisjectBoxOpen32;
_fontReference = new FontReference(Style.Current.FontSmall);
editor.Options.OptionsChanged += OnEditorOptionsChanged;
OnEditorOptionsChanged(editor.Options.Options);
}
private void OnEditorOptionsChanged(EditorOptions options)
{
float gizmoScale = options.Viewport.DirectionGizmoScale;
_axisLength = AxisLength * gizmoScale;
_spriteRadius = SpriteRadius * gizmoScale;
_gizmoBrightness = options.Viewport.DirectionGizmoBrightness;
_gizmoOpacity = options.Viewport.DirectionGizmoOpacity;
_backgroundOpacity = options.Viewport.DirectionGizmoBackgroundOpacity;
_fontReference.Size = 8.25f * gizmoScale;
}
private bool IsPointInSprite(Float2 point, Float2 spriteCenter)
{
Float2 delta = point - spriteCenter;
float distanceSq = delta.LengthSquared;
float radiusSq = _spriteRadius * _spriteRadius;
return distanceSq <= radiusSq;
}
/// <inheritdoc />
public override void OnMouseMove(Float2 location)
{
_hoveredAxisIndex = -1;
// Check which axis is being hovered - check from closest to farthest for proper layering
for (int i = _spritePositions.Count - 1; i >= 0; i--)
{
if (IsPointInSprite(location, _spritePositions[i].position))
{
_hoveredAxisIndex = i;
break;
}
}
base.OnMouseMove(location);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (base.OnMouseUp(location, button))
return true;
// Check which axis is being clicked - check from closest to farthest for proper layering
for (int i = _spritePositions.Count - 1; i >= 0; i--)
{
if (IsPointInSprite(location, _spritePositions[i].position))
{
OrientViewToAxis(_spritePositions[i].direction);
return true;
}
}
return false;
}
private void OrientViewToAxis(AxisDirection direction)
{
Quaternion orientation = direction switch
{
AxisDirection.PosX => Quaternion.Euler(0, -90, 0),
AxisDirection.NegX => Quaternion.Euler(0, 90, 0),
AxisDirection.PosY => Quaternion.Euler(90, 0, 0),
AxisDirection.NegY => Quaternion.Euler(-90, 0, 0),
AxisDirection.PosZ => Quaternion.Euler(0, 180, 0),
AxisDirection.NegZ => Quaternion.Euler(0, 0, 0),
_ => Quaternion.Identity
};
_viewport.OrientViewport(ref orientation);
}
/// <summary>
/// Used to Draw the gizmo.
/// </summary>
public override void DrawSelf()
{
base.DrawSelf();
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
_viewportProjection.Init(_owner.Viewport);
_gizmoCenter = _viewport.Task.View.WorldPosition + _viewport.Task.View.Direction * 1500;
_viewportProjection.ProjectPoint(_gizmoCenter, out var gizmoCenterScreen);
var relativeCenter = Size * 0.5f;
// Project unit vectors
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Right, out var xProjected);
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Up, out var yProjected);
_viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Forward, out var zProjected);
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Right, out var negXProjected);
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Up, out var negYProjected);
_viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Forward, out var negZProjected);
// Normalize by viewport height to keep size independent of FOV and viewport dimensions
float heightNormalization = _viewport.Height / 720.0f; // 720 = reference height
// Fix in axes distance no matter FOV/OrthoScale to keep consistent size regardless of zoom level
if (_owner.Viewport.UseOrthographicProjection)
heightNormalization /= _owner.Viewport.OrthographicScale * 0.5f;
else
{
// This could be some actual math expression, not that hack
var fov = _owner.Viewport.FieldOfView / 60.0f;
float scaleAt30 = 0.1f, scaleAt60 = 1.0f, scaleAt120 = 1.5f, scaleAt180 = 3.0f;
heightNormalization /= Mathf.Lerp(scaleAt30, scaleAt60, fov);
heightNormalization /= Mathf.Lerp(scaleAt60, scaleAt120, Mathf.Saturate(fov - 1));
heightNormalization /= Mathf.Lerp(scaleAt60, scaleAt180, Mathf.Saturate(fov - 2));
}
Float2 xDelta = (xProjected - gizmoCenterScreen) / heightNormalization;
Float2 yDelta = (yProjected - gizmoCenterScreen) / heightNormalization;
Float2 zDelta = (zProjected - gizmoCenterScreen) / heightNormalization;
Float2 negXDelta = (negXProjected - gizmoCenterScreen) / heightNormalization;
Float2 negYDelta = (negYProjected - gizmoCenterScreen) / heightNormalization;
Float2 negZDelta = (negZProjected - gizmoCenterScreen) / heightNormalization;
// Calculate distances from camera to determine draw order
Vector3 cameraPosition = _viewport.Task.View.Position;
float xDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Right);
float yDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Up);
float zDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Forward);
float negXDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Right);
float negYDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Up);
float negZDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Forward);
_xAxisData.Delta = xDelta;
_xAxisData.Distance = xDistance;
_yAxisData.Delta = yDelta;
_yAxisData.Distance = yDistance;
_zAxisData.Delta = zDelta;
_zAxisData.Distance = zDistance;
_negXAxisData.Delta = negXDelta;
_negXAxisData.Distance = negXDistance;
_negYAxisData.Delta = negYDelta;
_negYAxisData.Distance = negYDistance;
_negZAxisData.Delta = negZDelta;
_negZAxisData.Distance = negZDistance;
// Sort for correct draw order.
_axisData.Clear();
_axisData.AddRange([_xAxisData, _yAxisData, _zAxisData, _negXAxisData, _negYAxisData, _negZAxisData]);
_axisData.Sort((a, b) => -a.Distance.CompareTo(b.Distance));
// Rebuild sprite positions list for hover detection
_spritePositions.Clear();
Render2D.DrawSprite(_posHandle, new Rectangle(0, 0, Size), Color.Black.AlphaMultiplied(_backgroundOpacity));
// Draw in order from farthest to closest
for (int i = 0; i < _axisData.Count; i++)
{
var axis = _axisData[i];
Float2 tipScreen = relativeCenter + axis.Delta * _axisLength;
bool isHovered = _hoveredAxisIndex == i;
// Store sprite position for hover detection
_spritePositions.Add((tipScreen, axis.Direction));
var axisColor = isHovered ? new Color(1.0f, 0.8980392f, 0.039215688f) : axis.AxisColor;
axisColor = axisColor.RGBMultiplied(_gizmoBrightness).AlphaMultiplied(_gizmoOpacity);
var font = _fontReference.GetFont();
if (!axis.Negative)
{
Render2D.DrawLine(relativeCenter, tipScreen, axisColor, 1.5f);
Render2D.DrawSprite(_posHandle, new Rectangle(tipScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axisColor);
Render2D.DrawText(font, axis.Label, Color.Black, tipScreen - font.MeasureText(axis.Label) * 0.5f);
}
else
{
Render2D.DrawSprite(_posHandle, new Rectangle(tipScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axisColor.RGBMultiplied(0.85f).AlphaMultiplied(0.8f));
if (isHovered)
Render2D.DrawText(font, axis.Label, Color.Black, tipScreen - font.MeasureText(axis.Label) * 0.5f);
}
}
Render2D.Features = features;
}
}

View File

@@ -57,7 +57,7 @@ namespace FlaxEditor.Gizmo
var height = output.Height; var height = output.Height;
var desc = GPUTextureDescription.New2D(width, height, format, GPUTextureFlags.RenderTarget | GPUTextureFlags.ShaderResource, 1, 1, msaaLevel); var desc = GPUTextureDescription.New2D(width, height, format, GPUTextureFlags.RenderTarget | GPUTextureFlags.ShaderResource, 1, 1, msaaLevel);
var target = RenderTargetPool.Get(ref desc); var target = RenderTargetPool.Get(ref desc);
desc = GPUTextureDescription.New2D(width, height, renderContext.Buffers.DepthBuffer.Format, GPUTextureFlags.DepthStencil, 1, 1, msaaLevel); desc = GPUTextureDescription.New2D(width, height, PixelFormat.D24_UNorm_S8_UInt, GPUTextureFlags.DepthStencil, 1, 1, msaaLevel);
var targetDepth = RenderTargetPool.Get(ref desc); var targetDepth = RenderTargetPool.Get(ref desc);
// Copy frame and clear depth // Copy frame and clear depth

View File

@@ -529,7 +529,7 @@ namespace FlaxEditor
if (EnableBackground && _view != null) if (EnableBackground && _view != null)
{ {
// Draw background // Draw background
Surface.VisjectSurface.DrawBackgroundDefault(Editor.Instance.UI.VisjectSurfaceBackground, Size, _view.Location); Surface.VisjectSurface.DrawBackgroundDefault(Editor.Instance.UI.VisjectSurfaceBackground, Width, Height);
if (ShowGrid) if (ShowGrid)
{ {

View File

@@ -24,22 +24,22 @@ namespace FlaxEditor.Modules
private bool _rebuildInitFlag; private bool _rebuildInitFlag;
private int _itemsCreated; private int _itemsCreated;
private int _itemsDeleted; private int _itemsDeleted;
private readonly HashSet<MainContentFolderTreeNode> _dirtyNodes = new HashSet<MainContentFolderTreeNode>(); private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
/// <summary> /// <summary>
/// The project directory. /// The project directory.
/// </summary> /// </summary>
public ProjectFolderTreeNode Game { get; private set; } public ProjectTreeNode Game { get; private set; }
/// <summary> /// <summary>
/// The engine directory. /// The engine directory.
/// </summary> /// </summary>
public ProjectFolderTreeNode Engine { get; private set; } public ProjectTreeNode Engine { get; private set; }
/// <summary> /// <summary>
/// The list of all projects workspace directories (including game, engine and plugins projects). /// The list of all projects workspace directories (including game, engine and plugins projects).
/// </summary> /// </summary>
public readonly List<ProjectFolderTreeNode> Projects = new List<ProjectFolderTreeNode>(); public readonly List<ProjectTreeNode> Projects = new List<ProjectTreeNode>();
/// <summary> /// <summary>
/// The list with all content items proxy objects. Use <see cref="AddProxy"/> and <see cref="RemoveProxy"/> to modify this or <see cref="Rebuild"/> to refresh database when adding new item proxy types. /// The list with all content items proxy objects. Use <see cref="AddProxy"/> and <see cref="RemoveProxy"/> to modify this or <see cref="Rebuild"/> to refresh database when adding new item proxy types.
@@ -116,7 +116,7 @@ namespace FlaxEditor.Modules
/// </summary> /// </summary>
/// <param name="project">The project.</param> /// <param name="project">The project.</param>
/// <returns>The project workspace or null if not loaded into database.</returns> /// <returns>The project workspace or null if not loaded into database.</returns>
public ProjectFolderTreeNode GetProjectWorkspace(ProjectInfo project) public ProjectTreeNode GetProjectWorkspace(ProjectInfo project)
{ {
return Projects.FirstOrDefault(x => x.Project == project); return Projects.FirstOrDefault(x => x.Project == project);
} }
@@ -878,7 +878,7 @@ namespace FlaxEditor.Modules
} }
} }
private void LoadFolder(ContentFolderTreeNode node, bool checkSubDirs) private void LoadFolder(ContentTreeNode node, bool checkSubDirs)
{ {
if (node == null) if (node == null)
return; return;
@@ -957,7 +957,7 @@ namespace FlaxEditor.Modules
if (childFolderNode == null) if (childFolderNode == null)
{ {
// Create node // Create node
ContentFolderTreeNode n = new ContentFolderTreeNode(node, childPath); ContentTreeNode n = new ContentTreeNode(node, childPath);
if (!_isDuringFastSetup) if (!_isDuringFastSetup)
sortChildren = true; sortChildren = true;
@@ -982,7 +982,7 @@ namespace FlaxEditor.Modules
node.SortChildren(); node.SortChildren();
// Ignore some special folders // Ignore some special folders
if (node is MainContentFolderTreeNode mainNode && mainNode.Folder.ShortName == "Source") if (node is MainContentTreeNode mainNode && mainNode.Folder.ShortName == "Source")
{ {
var mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "obj")) as ContentFolder; var mainNodeChild = mainNode.Folder.Find(StringUtils.CombinePaths(mainNode.Path, "obj")) as ContentFolder;
if (mainNodeChild != null) if (mainNodeChild != null)
@@ -999,7 +999,7 @@ namespace FlaxEditor.Modules
} }
} }
private void LoadScripts(ContentFolderTreeNode parent, string[] files) private void LoadScripts(ContentTreeNode parent, string[] files)
{ {
for (int i = 0; i < files.Length; i++) for (int i = 0; i < files.Length; i++)
{ {
@@ -1045,7 +1045,7 @@ namespace FlaxEditor.Modules
} }
} }
private void LoadAssets(ContentFolderTreeNode parent, string[] files) private void LoadAssets(ContentTreeNode parent, string[] files)
{ {
for (int i = 0; i < files.Length; i++) for (int i = 0; i < files.Length; i++)
{ {
@@ -1097,20 +1097,20 @@ namespace FlaxEditor.Modules
var workspace = GetProjectWorkspace(project); var workspace = GetProjectWorkspace(project);
if (workspace == null) if (workspace == null)
{ {
workspace = new ProjectFolderTreeNode(project); workspace = new ProjectTreeNode(project);
Projects.Add(workspace); Projects.Add(workspace);
var contentFolder = StringUtils.CombinePaths(project.ProjectFolderPath, "Content"); var contentFolder = StringUtils.CombinePaths(project.ProjectFolderPath, "Content");
if (Directory.Exists(contentFolder)) if (Directory.Exists(contentFolder))
{ {
workspace.Content = new MainContentFolderTreeNode(workspace, ContentFolderType.Content, contentFolder); workspace.Content = new MainContentTreeNode(workspace, ContentFolderType.Content, contentFolder);
workspace.Content.Folder.ParentFolder = workspace.Folder; workspace.Content.Folder.ParentFolder = workspace.Folder;
} }
var sourceFolder = StringUtils.CombinePaths(project.ProjectFolderPath, "Source"); var sourceFolder = StringUtils.CombinePaths(project.ProjectFolderPath, "Source");
if (Directory.Exists(sourceFolder)) if (Directory.Exists(sourceFolder))
{ {
workspace.Source = new MainContentFolderTreeNode(workspace, ContentFolderType.Source, sourceFolder); workspace.Source = new MainContentTreeNode(workspace, ContentFolderType.Source, sourceFolder);
workspace.Source.Folder.ParentFolder = workspace.Folder; workspace.Source.Folder.ParentFolder = workspace.Folder;
} }
} }
@@ -1218,16 +1218,16 @@ namespace FlaxEditor.Modules
Proxy.Add(new GenericJsonAssetProxy()); Proxy.Add(new GenericJsonAssetProxy());
// Create content folders nodes // Create content folders nodes
Engine = new ProjectFolderTreeNode(Editor.EngineProject) Engine = new ProjectTreeNode(Editor.EngineProject)
{ {
Content = new MainContentFolderTreeNode(Engine, ContentFolderType.Content, Globals.EngineContentFolder), Content = new MainContentTreeNode(Engine, ContentFolderType.Content, Globals.EngineContentFolder),
}; };
if (Editor.GameProject != Editor.EngineProject) if (Editor.GameProject != Editor.EngineProject)
{ {
Game = new ProjectFolderTreeNode(Editor.GameProject) Game = new ProjectTreeNode(Editor.GameProject)
{ {
Content = new MainContentFolderTreeNode(Game, ContentFolderType.Content, Globals.ProjectContentFolder), Content = new MainContentTreeNode(Game, ContentFolderType.Content, Globals.ProjectContentFolder),
Source = new MainContentFolderTreeNode(Game, ContentFolderType.Source, Globals.ProjectSourceFolder), Source = new MainContentTreeNode(Game, ContentFolderType.Source, Globals.ProjectSourceFolder),
}; };
// TODO: why it's required? the code above should work for linking the nodes hierarchy // TODO: why it's required? the code above should work for linking the nodes hierarchy
Game.Content.Folder.ParentFolder = Game.Folder; Game.Content.Folder.ParentFolder = Game.Folder;
@@ -1307,7 +1307,7 @@ namespace FlaxEditor.Modules
} }
} }
internal void OnDirectoryEvent(MainContentFolderTreeNode node, FileSystemEventArgs e) internal void OnDirectoryEvent(MainContentTreeNode node, FileSystemEventArgs e)
{ {
// Ensure to be ready for external events // Ensure to be ready for external events
if (_isDuringFastSetup) if (_isDuringFastSetup)

View File

@@ -710,10 +710,6 @@ namespace FlaxEditor.Options
[EditorDisplay("Node Editors"), EditorOrder(4580)] [EditorDisplay("Node Editors"), EditorOrder(4580)]
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.A, KeyboardKeys.Alt); public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.A, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Shift+F")]
[EditorDisplay("Node Editors"), EditorOrder(4590)]
public InputBinding FocusSelectedNodes = new InputBinding(KeyboardKeys.F, KeyboardKeys.Shift);
#endregion #endregion
} }
} }

View File

@@ -253,6 +253,13 @@ namespace FlaxEditor.Options
[EditorDisplay("Interface"), EditorOrder(280), Tooltip("Editor content window orientation.")] [EditorDisplay("Interface"), EditorOrder(280), Tooltip("Editor content window orientation.")]
public FlaxEngine.GUI.Orientation ContentWindowOrientation { get; set; } = FlaxEngine.GUI.Orientation.Horizontal; public FlaxEngine.GUI.Orientation ContentWindowOrientation { get; set; } = FlaxEngine.GUI.Orientation.Horizontal;
/// <summary>
/// If checked, color pickers will always modify the color unless 'Cancel' if pressed, otherwise color won't change unless 'Ok' is pressed.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Interface"), EditorOrder(290)]
public bool AutoAcceptColorPickerChange { get; set; } = true;
/// <summary> /// <summary>
/// Gets or sets the formatting option for numeric values in the editor. /// Gets or sets the formatting option for numeric values in the editor.
/// </summary> /// </summary>

View File

@@ -171,40 +171,5 @@ namespace FlaxEditor.Options
[DefaultValue(1000.0f), Limit(0.0f, 20000.0f, 5.0f)] [DefaultValue(1000.0f), Limit(0.0f, 20000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(410)] [EditorDisplay("Viewport Icons"), EditorOrder(410)]
public float MaxSizeDistance { get; set; } = 1000.0f; public float MaxSizeDistance { get; set; } = 1000.0f;
/// <summary>
/// Gets or sets a value that indicates whether the main viewports <see cref="Gizmo.DirectionGizmo"/> is visible.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Direction Gizmo"), EditorOrder(500), Tooltip("Sets the visibility of the direction gizmo in the main editor viewport.")]
public bool ShowDirectionGizmo { get; set; } = true;
/// <summary>
/// Gets or sets a value by which the main viewports <see cref="Gizmo.DirectionGizmo"/> size is multiplied with.
/// </summary>
[DefaultValue(1f), Limit(0.0f, 2.0f)]
[EditorDisplay("Direction Gizmo"), EditorOrder(501), Tooltip("The scale of the direction gizmo in the main viewport.")]
public float DirectionGizmoScale { get; set; } = 1f;
/// <summary>
/// Gets or sets a value for the opacity of the main viewports <see cref="Gizmo.DirectionGizmo"/> background.
/// </summary>
[DefaultValue(0.1f), Limit(0.0f, 1.0f)]
[EditorDisplay("Direction Gizmo"), EditorOrder(502), Tooltip("The background opacity of the of the direction gizmo in the main viewport.")]
public float DirectionGizmoBackgroundOpacity { get; set; } = 0.1f;
/// <summary>
/// Gets or sets a value for the opacity of the main viewports <see cref="Gizmo.DirectionGizmo"/>.
/// </summary>
[DefaultValue(0.6f), Limit(0.0f, 1.0f)]
[EditorDisplay("Direction Gizmo"), EditorOrder(503), Tooltip("The opacity of the of the direction gizmo in the main viewport.")]
public float DirectionGizmoOpacity { get; set; } = 0.6f;
/// <summary>
/// Gets or sets a value for the opacity of the main viewports <see cref="Gizmo.DirectionGizmo"/>.
/// </summary>
[DefaultValue(1f), Limit(0.0f, 2.0f)]
[EditorDisplay("Direction Gizmo"), EditorOrder(504), Tooltip("The brightness of the of the direction gizmo in the main viewport.")]
public float DirectionGizmoBrightness{ get; set; } = 1f;
} }
} }

View File

@@ -1,29 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine;
namespace FlaxEditor.SceneGraph.Actors
{
/// <summary>
/// Scene tree node for <see cref="Cloth"/> actor type.
/// </summary>
[HideInEditor]
public sealed class ClothNode : ActorNode
{
/// <inheritdoc />
public ClothNode(Actor actor)
: base(actor)
{
}
/// <inheritdoc />
public override void PostSpawn()
{
base.PostSpawn();
// Snap to the parent
if (!(ParentNode is SceneNode))
Actor.LocalTransform = Transform.Identity;
}
}
}

View File

@@ -1,29 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine;
namespace FlaxEditor.SceneGraph.Actors
{
/// <summary>
/// Scene tree node for <see cref="RigidBody"/> actor type.
/// </summary>
[HideInEditor]
public sealed class RigidBodyNode : ActorNode
{
/// <inheritdoc />
public RigidBodyNode(Actor actor)
: base(actor)
{
}
/// <inheritdoc />
public override void PostSpawn()
{
base.PostSpawn();
if (HasPrefabLink)
return;
Actor.StaticFlags = StaticFlags.None;
}
}
}

View File

@@ -324,12 +324,13 @@ namespace FlaxEditor.SceneGraph.GUI
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id); isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id);
} }
if (!noFilter) if (isExpanded)
{ {
if (isExpanded) Expand(true);
Expand(true); }
else else
Collapse(true); {
Collapse(true);
} }
Visible = isThisVisible | isAnyChildVisible; Visible = isThisVisible | isAnyChildVisible;

View File

@@ -51,7 +51,6 @@ namespace FlaxEditor.SceneGraph
CustomNodesTypes.Add(typeof(AudioSource), typeof(AudioSourceNode)); CustomNodesTypes.Add(typeof(AudioSource), typeof(AudioSourceNode));
CustomNodesTypes.Add(typeof(BoneSocket), typeof(BoneSocketNode)); CustomNodesTypes.Add(typeof(BoneSocket), typeof(BoneSocketNode));
CustomNodesTypes.Add(typeof(Decal), typeof(DecalNode)); CustomNodesTypes.Add(typeof(Decal), typeof(DecalNode));
CustomNodesTypes.Add(typeof(Cloth), typeof(ClothNode));
CustomNodesTypes.Add(typeof(BoxCollider), typeof(BoxColliderNode)); CustomNodesTypes.Add(typeof(BoxCollider), typeof(BoxColliderNode));
CustomNodesTypes.Add(typeof(SphereCollider), typeof(ColliderNode)); CustomNodesTypes.Add(typeof(SphereCollider), typeof(ColliderNode));
CustomNodesTypes.Add(typeof(CapsuleCollider), typeof(ColliderNode)); CustomNodesTypes.Add(typeof(CapsuleCollider), typeof(ColliderNode));
@@ -74,7 +73,6 @@ namespace FlaxEditor.SceneGraph
CustomNodesTypes.Add(typeof(NavMesh), typeof(ActorNode)); CustomNodesTypes.Add(typeof(NavMesh), typeof(ActorNode));
CustomNodesTypes.Add(typeof(SpriteRender), typeof(SpriteRenderNode)); CustomNodesTypes.Add(typeof(SpriteRender), typeof(SpriteRenderNode));
CustomNodesTypes.Add(typeof(Joint), typeof(JointNode)); CustomNodesTypes.Add(typeof(Joint), typeof(JointNode));
CustomNodesTypes.Add(typeof(RigidBody), typeof(RigidBodyNode));
} }
/// <summary> /// <summary>

View File

@@ -102,14 +102,8 @@ namespace FlaxEditor.Surface.Archetypes
outline = style.BorderHighlighted; outline = style.BorderHighlighted;
else if (_editor._node.SelectedAnimationIndex == _index) else if (_editor._node.SelectedAnimationIndex == _index)
outline = style.BackgroundSelected; outline = style.BackgroundSelected;
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
Render2D.DrawSprite(icon, rect.MakeExpanded(4.0f), outline); Render2D.DrawSprite(icon, rect.MakeExpanded(4.0f), outline);
Render2D.DrawSprite(icon, rect, style.Foreground); Render2D.DrawSprite(icon, rect, style.Foreground);
Render2D.Features = features;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -569,9 +563,6 @@ namespace FlaxEditor.Surface.Archetypes
// Grid // Grid
_node.DrawEditorGrid(ref rect); _node.DrawEditorGrid(ref rect);
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
base.Draw(); base.Draw();
// Draw debug position // Draw debug position
@@ -587,8 +578,6 @@ namespace FlaxEditor.Surface.Archetypes
Render2D.DrawSprite(icon, debugRect, style.ProgressNormal); Render2D.DrawSprite(icon, debugRect, style.ProgressNormal);
} }
Render2D.Features = features;
// Frame // Frame
var frameColor = containsFocus ? style.BackgroundSelected : (IsMouseOver ? style.ForegroundGrey : style.ForegroundDisabled); var frameColor = containsFocus ? style.BackgroundSelected : (IsMouseOver ? style.ForegroundGrey : style.ForegroundDisabled);
Render2D.DrawRectangle(new Rectangle(1, 1, rect.Width - 2, rect.Height - 2), frameColor); Render2D.DrawRectangle(new Rectangle(1, 1, rect.Width - 2, rect.Height - 2), frameColor);

View File

@@ -79,7 +79,7 @@ namespace FlaxEditor.Surface.Archetypes
: base(id, context, nodeArch, groupArch) : base(id, context, nodeArch, groupArch)
{ {
var marginX = FlaxEditor.Surface.Constants.NodeMarginX; var marginX = FlaxEditor.Surface.Constants.NodeMarginX;
var uiStartPosY = FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight; var uiStartPosY = FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize;
var editButton = new Button(marginX, uiStartPosY, 246, 20) var editButton = new Button(marginX, uiStartPosY, 246, 20)
{ {

View File

@@ -70,9 +70,6 @@ namespace FlaxEditor.Surface.Archetypes
if (box.ID != _assetBox.ID) if (box.ID != _assetBox.ID)
return; return;
_assetSelect.Visible = !box.HasAnyConnection; _assetSelect.Visible = !box.HasAnyConnection;
if (!Archetype.Flags.HasFlag(NodeFlags.FixedSize))
ResizeAuto();
} }
} }
@@ -246,8 +243,8 @@ namespace FlaxEditor.Surface.Archetypes
{ {
Type = NodeElementType.Input, Type = NodeElementType.Input,
Position = new Float2( Position = new Float2(
FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginX - FlaxEditor.Surface.Constants.BoxOffsetX,
FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight + ylevel * FlaxEditor.Surface.Constants.LayoutOffsetY), FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize + ylevel * FlaxEditor.Surface.Constants.LayoutOffsetY),
Text = "Pose " + _blendPoses.Count, Text = "Pose " + _blendPoses.Count,
Single = true, Single = true,
ValueIndex = -1, ValueIndex = -1,
@@ -266,7 +263,7 @@ namespace FlaxEditor.Surface.Archetypes
private void UpdateHeight() private void UpdateHeight()
{ {
float nodeHeight = 10 + (Mathf.Max(_blendPoses.Count, 1) + 3) * FlaxEditor.Surface.Constants.LayoutOffsetY; float nodeHeight = 10 + (Mathf.Max(_blendPoses.Count, 1) + 3) * FlaxEditor.Surface.Constants.LayoutOffsetY;
Height = nodeHeight + FlaxEditor.Surface.Constants.NodeMarginY * 2 + FlaxEditor.Surface.Constants.NodeHeaderHeight + FlaxEditor.Surface.Constants.NodeFooterSize; Height = nodeHeight + FlaxEditor.Surface.Constants.NodeMarginY * 2 + FlaxEditor.Surface.Constants.NodeHeaderSize + FlaxEditor.Surface.Constants.NodeFooterSize;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -624,8 +621,8 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new MultiBlend1D(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new MultiBlend1D(id, context, arch, groupArch),
Title = "Multi Blend 1D", Title = "Multi Blend 1D",
Description = "Animation blending in 1D", Description = "Animation blending in 1D",
Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize | NodeFlags.FixedSize, Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize,
Size = new Float2(420, 320), Size = new Float2(420, 300),
DefaultValues = new object[] DefaultValues = new object[]
{ {
// Node data // Node data
@@ -649,9 +646,9 @@ namespace FlaxEditor.Surface.Archetypes
// Axis X // Axis X
NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4), NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4),
NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY, "(min: max: )"), NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
NodeElementArchetype.Factory.Vector_X(60, 3 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_X(60, 3 * Surface.Constants.LayoutOffsetY + 2, 0),
NodeElementArchetype.Factory.Vector_Y(145, 3 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_Y(145, 3 * Surface.Constants.LayoutOffsetY + 2, 0),
} }
}, },
new NodeArchetype new NodeArchetype
@@ -660,8 +657,8 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new MultiBlend2D(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new MultiBlend2D(id, context, arch, groupArch),
Title = "Multi Blend 2D", Title = "Multi Blend 2D",
Description = "Animation blending in 2D", Description = "Animation blending in 2D",
Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize | NodeFlags.FixedSize, Flags = NodeFlags.AnimGraph | NodeFlags.VariableValuesSize,
Size = new Float2(420, 640), Size = new Float2(420, 620),
DefaultValues = new object[] DefaultValues = new object[]
{ {
// Node data // Node data
@@ -685,15 +682,15 @@ namespace FlaxEditor.Surface.Archetypes
// Axis X // Axis X
NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4), NodeElementArchetype.Factory.Input(3, "X", true, typeof(float), 4),
NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY, "(min: max: )"), NodeElementArchetype.Factory.Text(30, 3 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
NodeElementArchetype.Factory.Vector_X(60, 3 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_X(60, 3 * Surface.Constants.LayoutOffsetY + 2, 0),
NodeElementArchetype.Factory.Vector_Y(145, 3 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_Y(145, 3 * Surface.Constants.LayoutOffsetY + 2, 0),
// Axis Y // Axis Y
NodeElementArchetype.Factory.Input(4, "Y", true, typeof(float), 5), NodeElementArchetype.Factory.Input(4, "Y", true, typeof(float), 5),
NodeElementArchetype.Factory.Text(30, 4 * Surface.Constants.LayoutOffsetY, "(min: max: )"), NodeElementArchetype.Factory.Text(30, 4 * Surface.Constants.LayoutOffsetY + 2, "(min: max: )"),
NodeElementArchetype.Factory.Vector_Z(60, 4 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_Z(60, 4 * Surface.Constants.LayoutOffsetY + 2, 0),
NodeElementArchetype.Factory.Vector_W(145, 4 * Surface.Constants.LayoutOffsetY, 0), NodeElementArchetype.Factory.Vector_W(145, 4 * Surface.Constants.LayoutOffsetY + 2, 0),
} }
}, },
new NodeArchetype new NodeArchetype
@@ -934,7 +931,7 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 27, TypeID = 27,
Title = "Copy Node", Title = "Copy Node",
Description = "Copies the skeleton node transformation data (in local space)", Description = "Copies the skeleton node transformation data (in local space)",
Flags = NodeFlags.AnimGraph | NodeFlags.FixedSize, Flags = NodeFlags.AnimGraph,
Size = new Float2(260, 140), Size = new Float2(260, 140),
DefaultValues = new object[] DefaultValues = new object[]
{ {

View File

@@ -189,69 +189,13 @@ namespace FlaxEditor.Surface.Archetypes
public override void Draw() public override void Draw()
{ {
var style = Style.Current; base.Draw();
var backgroundRect = new Rectangle(Float2.Zero, Size);
// Shadow
if (DrawBasicShadow)
{
var shadowRect = backgroundRect.MakeOffsetted(ShadowOffset);
Render2D.FillRectangle(shadowRect, Color.Black.AlphaMultiplied(0.125f));
}
// Background
Render2D.FillRectangle(backgroundRect, BackgroundColor);
// Breakpoint hit
if (Breakpoint.Hit)
{
var colorTop = Color.OrangeRed;
var colorBottom = Color.Red;
var time = DateTime.Now - Engine.StartupTime;
Render2D.DrawRectangle(backgroundRect.MakeExpanded(Mathf.Lerp(3.0f, 12.0f, Mathf.Sin((float)time.TotalSeconds * 10.0f) * 0.5f + 0.5f)), colorTop, colorTop, colorBottom, colorBottom, 2.0f);
}
// Header
var headerColor = style.BackgroundHighlighted;
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting)
headerColor *= 1.07f;
Render2D.FillRectangle(_headerRect, style.BackgroundHighlighted);
Render2D.DrawText(style.FontLarge, Title, _headerTextRect, style.Foreground, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1f, FlaxEditor.Surface.Constants.NodeHeaderTextScale);
// Close button
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
{
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting;
DrawCloseButton(_closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
}
DrawChildren();
// Selection outline
if (_isSelected)
{
var colorTop = Color.Orange;
var colorBottom = Color.OrangeRed;
Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom, 2.5f);
}
// Breakpoint dot
if (Breakpoint.Set)
{
var icon = Breakpoint.Enabled ? Surface.Style.Icons.BoxClose : Surface.Style.Icons.BoxOpen;
Render2D.DrawSprite(icon, new Rectangle(-7, -7, 16, 16), new Color(0.9f, 0.9f, 0.9f));
Render2D.DrawSprite(icon, new Rectangle(-6, -6, 14, 14), new Color(0.894117647f, 0.0784313725f, 0.0f));
}
if (highlightBox != null)
Render2D.DrawRectangle(highlightBox.Bounds, style.BorderHighlighted, 2f);
// Debug Info // Debug Info
if (!string.IsNullOrEmpty(_debugInfo)) if (!string.IsNullOrEmpty(_debugInfo))
{ {
// Draw an extra background to cover the archetype color colored node background and make text more legible var style = Style.Current;
Render2D.FillRectangle(new Rectangle(0, _headerRect.Bottom + 4, Width, Height - _headerRect.Bottom - 4), style.BackgroundHighlighted); Render2D.DrawText(style.FontSmall, _debugInfo, new Rectangle(4, _headerRect.Bottom + 4, _debugInfoSize), style.Foreground);
Render2D.DrawText(style.FontSmall, _debugInfo, new Rectangle(4, _headerRect.Bottom + 7, _debugInfoSize), style.Foreground, scale: 0.8f);
} }
// Debug relevancy outline // Debug relevancy outline
@@ -259,7 +203,7 @@ namespace FlaxEditor.Surface.Archetypes
{ {
var colorTop = Color.LightYellow; var colorTop = Color.LightYellow;
var colorBottom = Color.Yellow; var colorBottom = Color.Yellow;
backgroundRect = new Rectangle(Float2.One, Size - new Float2(2.0f)); var backgroundRect = new Rectangle(Float2.One, Size - new Float2(2.0f));
Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom); Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom);
} }
} }
@@ -471,8 +415,8 @@ namespace FlaxEditor.Surface.Archetypes
// Setup boxes // Setup boxes
_input = (InputBox)GetBox(0); _input = (InputBox)GetBox(0);
_output = (OutputBox)GetBox(1); _output = (OutputBox)GetBox(1);
_input.ConnectionOffset = new Float2(0, FlaxEditor.Surface.Constants.BoxRowHeight * -0.5f); _input.ConnectionOffset = new Float2(0, FlaxEditor.Surface.Constants.BoxSize * -0.5f);
_output.ConnectionOffset = new Float2(0, FlaxEditor.Surface.Constants.BoxRowHeight * 0.5f); _output.ConnectionOffset = new Float2(0, FlaxEditor.Surface.Constants.BoxSize * 0.5f);
// Setup node type and data // Setup node type and data
var flagsRoot = NodeFlags.NoRemove | NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaPaste; var flagsRoot = NodeFlags.NoRemove | NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaPaste;
@@ -571,7 +515,7 @@ namespace FlaxEditor.Surface.Archetypes
height += decorator.Height + DecoratorsMarginY; height += decorator.Height + DecoratorsMarginY;
width = Mathf.Max(width, decorator.Width - FlaxEditor.Surface.Constants.NodeCloseButtonSize - 2 * DecoratorsMarginX); width = Mathf.Max(width, decorator.Width - FlaxEditor.Surface.Constants.NodeCloseButtonSize - 2 * DecoratorsMarginX);
} }
Size = new Float2(width + FlaxEditor.Surface.Constants.NodeMarginX * 2 + FlaxEditor.Surface.Constants.NodeCloseButtonSize, height + FlaxEditor.Surface.Constants.NodeHeaderHeight); Size = new Float2(width + FlaxEditor.Surface.Constants.NodeMarginX * 2 + FlaxEditor.Surface.Constants.NodeCloseButtonSize, height + FlaxEditor.Surface.Constants.NodeHeaderSize + FlaxEditor.Surface.Constants.NodeFooterSize);
UpdateRectangles(); UpdateRectangles();
} }
@@ -592,13 +536,13 @@ namespace FlaxEditor.Surface.Archetypes
if (decorator.IndexInParent < indexInParent) if (decorator.IndexInParent < indexInParent)
decorator.IndexInParent = indexInParent + 1; // Push elements above the node decorator.IndexInParent = indexInParent + 1; // Push elements above the node
} }
const float footerSize = FlaxEditor.Surface.Constants.NodeFooterSize;
const float headerHeight = FlaxEditor.Surface.Constants.NodeHeaderHeight; const float headerSize = FlaxEditor.Surface.Constants.NodeHeaderSize;
const float closeButtonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin; const float closeButtonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin;
float closeButtonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize * 0.75f; const float closeButtonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize;
_headerRect = new Rectangle(0, bounds.Y - Y, bounds.Width, headerHeight); _headerRect = new Rectangle(0, bounds.Y - Y, bounds.Width, headerSize);
_headerTextRect = _headerRect with { X = 5f, Width = Width - closeButtonSize - closeButtonMargin * 4f };
_closeButtonRect = new Rectangle(bounds.Width - closeButtonSize - closeButtonMargin, _headerRect.Y + closeButtonMargin, closeButtonSize, closeButtonSize); _closeButtonRect = new Rectangle(bounds.Width - closeButtonSize - closeButtonMargin, _headerRect.Y + closeButtonMargin, closeButtonSize, closeButtonSize);
_footerRect = new Rectangle(0, bounds.Height - footerSize, bounds.Width, footerSize);
if (_output != null && _output.Visible) if (_output != null && _output.Visible)
{ {
_footerRect.Y -= ConnectionAreaHeight; _footerRect.Y -= ConnectionAreaHeight;
@@ -704,8 +648,6 @@ namespace FlaxEditor.Surface.Archetypes
private DragDecorator _dragDecorator; private DragDecorator _dragDecorator;
private float _dragLocation = -1; private float _dragLocation = -1;
internal override bool DrawBasicShadow => false;
internal Decorator(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) internal Decorator(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch) : base(id, context, nodeArch, groupArch)
{ {
@@ -725,7 +667,7 @@ namespace FlaxEditor.Surface.Archetypes
} }
} }
protected override Color ArchetypeColor => Color.Transparent; protected override Color FooterColor => Color.Transparent;
protected override Float2 CalculateNodeSize(float width, float height) protected override Float2 CalculateNodeSize(float width, float height)
{ {
@@ -734,7 +676,7 @@ namespace FlaxEditor.Surface.Archetypes
width = Mathf.Max(width, _debugInfoSize.X + 8.0f); width = Mathf.Max(width, _debugInfoSize.X + 8.0f);
height += _debugInfoSize.Y + 8.0f; height += _debugInfoSize.Y + 8.0f;
} }
return new Float2(width + FlaxEditor.Surface.Constants.NodeCloseButtonSize * 2 + DecoratorsMarginX * 2, height + FlaxEditor.Surface.Constants.NodeHeaderHeight); return new Float2(width + FlaxEditor.Surface.Constants.NodeCloseButtonSize * 2 + DecoratorsMarginX * 2, height + FlaxEditor.Surface.Constants.NodeHeaderSize);
} }
protected override void UpdateRectangles() protected override void UpdateRectangles()
@@ -742,14 +684,8 @@ namespace FlaxEditor.Surface.Archetypes
base.UpdateRectangles(); base.UpdateRectangles();
_footerRect = Rectangle.Empty; _footerRect = Rectangle.Empty;
const float closeButtonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin;
float closeButtonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize * 0.75f;
_closeButtonRect = new Rectangle(Bounds.Width - closeButtonSize - closeButtonMargin, _headerRect.Y + closeButtonMargin, closeButtonSize, closeButtonSize);
if (_dragIcon != null) if (_dragIcon != null)
{ _dragIcon.Bounds = new Rectangle(_closeButtonRect.X - _closeButtonRect.Width, _closeButtonRect.Y, _closeButtonRect.Size);
var dragIconRect = _closeButtonRect.MakeExpanded(5f);
_dragIcon.Bounds = new Rectangle(dragIconRect.X - dragIconRect.Width, dragIconRect.Y, dragIconRect.Size);
}
} }
protected override void UpdateTitle() protected override void UpdateTitle()
@@ -818,21 +754,16 @@ namespace FlaxEditor.Surface.Archetypes
{ {
base.OnSurfaceLoaded(action); base.OnSurfaceLoaded(action);
var node = Node;
if (action == SurfaceNodeActions.Undo) if (action == SurfaceNodeActions.Undo)
{ {
// Update parent node layout when restoring decorator from undo // Update parent node layout when restoring decorator from undo
var node = Node;
if (node != null) if (node != null)
{ {
node._decorators = null; node._decorators = null;
node.ResizeAuto(); node.ResizeAuto();
} }
} }
else
{
// Correctly size decorators when surface is loaded
node?.ResizeAuto();
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -173,10 +173,10 @@ namespace FlaxEditor.Surface.Archetypes
{ {
Op(1, "==", "Determines whether two values are equal", new[] { "equals" }), Op(1, "==", "Determines whether two values are equal", new[] { "equals" }),
Op(2, "!=", "Determines whether two values are not equal", new[] { "not equals" }), Op(2, "!=", "Determines whether two values are not equal", new[] { "not equals" }),
Op(3, ">", "Determines whether the first value is greater than the other", new[] { "greater than", "larger than", "bigger than", "more than" }), Op(3, ">", "Determines whether the first value is greater than the other", new[] { "greater than", "larger than", "bigger than" }),
Op(4, "<", "Determines whether the first value is less than the other", new[] { "less than", "smaller than", "tinier than" }), Op(4, "<", "Determines whether the first value is less than the other", new[] { "less than", "smaller than" }),
Op(5, "<=", "Determines whether the first value is less or equal to the other", new[] { "less equals than", "smaller equals than", "tinier equals than" }), Op(5, "<=", "Determines whether the first value is less or equal to the other", new[] { "less equals than", "smaller equals than" }),
Op(6, ">=", "Determines whether the first value is greater or equal to the other", new[] { "greater equals than", "larger equals than", "bigger equals than", "more equals than" }), Op(6, ">=", "Determines whether the first value is greater or equal to the other", new[] { "greater equals than", "larger equals than", "bigger equals than" }),
new NodeArchetype new NodeArchetype
{ {
TypeID = 7, TypeID = 7,

View File

@@ -166,7 +166,7 @@ namespace FlaxEditor.Surface.Archetypes
_picker = new EnumComboBox(type) _picker = new EnumComboBox(type)
{ {
EnumTypeValue = Values[0], EnumTypeValue = Values[0],
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, FlaxEditor.Surface.Constants.BoxRowHeight), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_picker.ValueChanged += () => SetValue(0, _picker.EnumTypeValue); _picker.ValueChanged += () => SetValue(0, _picker.EnumTypeValue);
@@ -218,7 +218,7 @@ namespace FlaxEditor.Surface.Archetypes
_output = (OutputBox)Elements[0]; _output = (OutputBox)Elements[0];
_typePicker = new TypePickerControl _typePicker = new TypePickerControl
{ {
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_typePicker.ValueChanged += () => Set(3); _typePicker.ValueChanged += () => Set(3);
@@ -362,7 +362,7 @@ namespace FlaxEditor.Surface.Archetypes
_output = (OutputBox)Elements[0]; _output = (OutputBox)Elements[0];
_keyTypePicker = new TypePickerControl _keyTypePicker = new TypePickerControl
{ {
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_keyTypePicker.ValueChanged += OnKeyTypeChanged; _keyTypePicker.ValueChanged += OnKeyTypeChanged;
@@ -482,7 +482,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(bool))),
Description = "Constant boolean value", Description = "Constant boolean value",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(90, 20), Size = new Float2(110, 20),
DefaultValues = new object[] DefaultValues = new object[]
{ {
false false
@@ -515,7 +515,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(int))), Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(int))),
Description = "Constant integer value", Description = "Constant integer value",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(120, 20), Size = new Float2(110, 20),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0 0
@@ -543,7 +543,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(float))), Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(float))),
Description = "Constant floating point", Description = "Constant floating point",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(120, 20), Size = new Float2(110, 20),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0.0f 0.0f
@@ -750,7 +750,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "PI", Title = "PI",
Description = "A value specifying the approximation of π which is 180 degrees", Description = "A value specifying the approximation of π which is 180 degrees",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(45, 20), Size = new Float2(50, 20),
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "π", typeof(float), 0), NodeElementArchetype.Factory.Output(0, "π", typeof(float), 0),
@@ -782,7 +782,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(uint))),
Description = "Constant unsigned integer value", Description = "Constant unsigned integer value",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(130, 20), Size = new Float2(170, 20),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0u 0u
@@ -824,7 +824,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(double))), Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(double))),
Description = "Constant floating point", Description = "Constant floating point",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(120, 20), Size = new Float2(110, 20),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0.0d 0.0d

View File

@@ -267,7 +267,7 @@ namespace FlaxEditor.Surface.Archetypes
{ {
_nameField = new Label _nameField = new Label
{ {
Size = new Float2(140, FlaxEditor.Surface.Constants.BoxRowHeight), Width = 140.0f,
TextColorHighlighted = Style.Current.ForegroundGrey, TextColorHighlighted = Style.Current.ForegroundGrey,
HorizontalAlignment = TextAlignment.Near, HorizontalAlignment = TextAlignment.Near,
Parent = this, Parent = this,
@@ -386,7 +386,8 @@ namespace FlaxEditor.Surface.Archetypes
_types = surface.FunctionTypes; _types = surface.FunctionTypes;
_typePicker = new ComboBox _typePicker = new ComboBox
{ {
Bounds = new Rectangle(4, 34, 80, FlaxEditor.Surface.Constants.BoxRowHeight), Location = new Float2(4, 32),
Width = 80.0f,
Parent = this, Parent = this,
}; };
for (int i = 0; i < _types.Length; i++) for (int i = 0; i < _types.Length; i++)
@@ -454,7 +455,8 @@ namespace FlaxEditor.Surface.Archetypes
_types = surface.FunctionTypes; _types = surface.FunctionTypes;
_typePicker = new ComboBox _typePicker = new ComboBox
{ {
Bounds = new Rectangle(24, 34, 80, FlaxEditor.Surface.Constants.BoxRowHeight), Location = new Float2(24, 32),
Width = 80.0f,
Parent = this, Parent = this,
}; };
for (int i = 0; i < _types.Length; i++) for (int i = 0; i < _types.Length; i++)
@@ -629,7 +631,7 @@ namespace FlaxEditor.Surface.Archetypes
} }
/// <inheritdoc /> /// <inheritdoc />
protected override Color ArchetypeColor => new Color(200, 11, 112); protected override Color FooterColor => new Color(200, 11, 112);
/// <inheritdoc /> /// <inheritdoc />
public override void OnLoaded(SurfaceNodeActions action) public override void OnLoaded(SurfaceNodeActions action)

View File

@@ -52,7 +52,6 @@ namespace FlaxEditor.Surface.Archetypes
}, },
new NodeArchetype new NodeArchetype
{ {
// [Deprecated]
TypeID = 3, TypeID = 3,
Title = "Pack Material Layer", Title = "Pack Material Layer",
Description = "Pack material properties", Description = "Pack material properties",
@@ -76,7 +75,6 @@ namespace FlaxEditor.Surface.Archetypes
}, },
new NodeArchetype new NodeArchetype
{ {
// [Deprecated]
TypeID = 4, TypeID = 4,
Title = "Unpack Material Layer", Title = "Unpack Material Layer",
Description = "Unpack material properties", Description = "Unpack material properties",
@@ -122,7 +120,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 6, TypeID = 6,
Title = "Pack Material Layer", Title = "Pack Material Layer",
Description = "Pack material properties", Description = "Pack material properties",
AlternativeTitles = new[] { "Make Material Layer", "Construct Material Layer", "Compose Material Layer" },
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(200, 280), Size = new Float2(200, 280),
Elements = new[] Elements = new[]
@@ -149,7 +146,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 7, TypeID = 7,
Title = "Unpack Material Layer", Title = "Unpack Material Layer",
Description = "Unpack material properties", Description = "Unpack material properties",
AlternativeTitles = new[] { "Break Material Layer", "Deconstruct Material Layer", "Decompose Material Layer", "Split Material Layer" },
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(210, 280), Size = new Float2(210, 280),
Elements = new[] Elements = new[]

View File

@@ -312,17 +312,16 @@ namespace FlaxEditor.Surface.Archetypes
: base(id, context, nodeArch, groupArch) : base(id, context, nodeArch, groupArch)
{ {
_sizeValueIndex = Archetype.TypeID == 8 ? 1 : 3; // Index of the Size stored in Values array _sizeValueIndex = Archetype.TypeID == 8 ? 1 : 3; // Index of the Size stored in Values array
Float2 pos = new Float2(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight), size; Float2 pos = new Float2(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize), size;
if (nodeArch.TypeID == 8) if (nodeArch.TypeID == 8)
{ {
pos += new Float2(65, 0); pos += new Float2(60, 0);
size = new Float2(160, 185); size = new Float2(172, 200);
_sizeMin = new Float2(240, 185);
} }
else else
{ {
pos += new Float2(0, 40 + FlaxEditor.Utilities.Constants.UIMargin * 2f); pos += new Float2(0, 40);
size = new Float2(300, 180); size = new Float2(300, 200);
} }
_textBox = new CustomCodeTextBox _textBox = new CustomCodeTextBox
{ {
@@ -507,8 +506,8 @@ namespace FlaxEditor.Surface.Archetypes
Size = new Float2(300, 200), Size = new Float2(300, 200),
DefaultValues = new object[] DefaultValues = new object[]
{ {
"// You can add HLSL code here\nOutput0 = Input0;", "// Here you can add HLSL code\nOutput0 = Input0;",
new Float2(350, 200), new Float2(300, 200),
}, },
Elements = new[] Elements = new[]
{ {
@@ -932,7 +931,7 @@ namespace FlaxEditor.Surface.Archetypes
new NodeArchetype new NodeArchetype
{ {
TypeID = 36, TypeID = 36,
Title = "HSV To RGB", Title = "HSVToRGB",
Description = "Converts a HSV value to linear RGB [X = 0/360, Y = 0/1, Z = 0/1]", Description = "Converts a HSV value to linear RGB [X = 0/360, Y = 0/1, Z = 0/1]",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 25), Size = new Float2(160, 25),
@@ -949,7 +948,7 @@ namespace FlaxEditor.Surface.Archetypes
new NodeArchetype new NodeArchetype
{ {
TypeID = 37, TypeID = 37,
Title = "RGB To HSV", Title = "RGBToHSV",
Description = "Converts a linear RGB value to HSV [X = 0/360, Y = 0/1, Z = 0/1]", Description = "Converts a linear RGB value to HSV [X = 0/360, Y = 0/1, Z = 0/1]",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 25), Size = new Float2(160, 25),
@@ -973,7 +972,7 @@ namespace FlaxEditor.Surface.Archetypes
Size = new Float2(300, 240), Size = new Float2(300, 240),
DefaultValues = new object[] DefaultValues = new object[]
{ {
"// You can add HLSL code here\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}", "// Here you can add HLSL code\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}",
true, true,
(int)MaterialTemplateInputsMapping.Utilities, (int)MaterialTemplateInputsMapping.Utilities,
new Float2(300, 240), new Float2(300, 240),

View File

@@ -213,7 +213,7 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 30, TypeID = 30,
Title = "Vector Transform", Title = "Vector Transform",
Description = "Transform vector from source space to destination space", Description = "Transform vector from source space to destination space",
Flags = NodeFlags.MaterialGraph | NodeFlags.FixedSize, Flags = NodeFlags.MaterialGraph,
Size = new Float2(170, 40), Size = new Float2(170, 40),
DefaultValues = new object[] DefaultValues = new object[]
{ {

View File

@@ -342,7 +342,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 20, TypeID = 20,
Title = "Pack Float2", Title = "Pack Float2",
Description = "Pack components to Float2", Description = "Pack components to Float2",
AlternativeTitles = new[] { "Make Float2", "Construct Float2", "Compose Float2" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 40), Size = new Float2(150, 40),
DefaultValues = new object[] DefaultValues = new object[]
@@ -362,7 +361,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 21, TypeID = 21,
Title = "Pack Float3", Title = "Pack Float3",
Description = "Pack components to Float3", Description = "Pack components to Float3",
AlternativeTitles = new[] { "Make Float3", "Construct Float3", "Compose Float3" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 60), Size = new Float2(150, 60),
DefaultValues = new object[] DefaultValues = new object[]
@@ -384,7 +382,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 22, TypeID = 22,
Title = "Pack Float4", Title = "Pack Float4",
Description = "Pack components to Float4", Description = "Pack components to Float4",
AlternativeTitles = new[] { "Make Float4", "Construct Float4", "Compose Float4" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 80), Size = new Float2(150, 80),
DefaultValues = new object[] DefaultValues = new object[]
@@ -408,7 +405,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 23, TypeID = 23,
Title = "Pack Rotation", Title = "Pack Rotation",
Description = "Pack components to Rotation", Description = "Pack components to Rotation",
AlternativeTitles = new[] { "Make Rotation", "Construct Rotation", "Compose Rotation" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 60), Size = new Float2(150, 60),
DefaultValues = new object[] DefaultValues = new object[]
@@ -430,7 +426,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 24, TypeID = 24,
Title = "Pack Transform", Title = "Pack Transform",
Description = "Pack components to Transform", Description = "Pack components to Transform",
AlternativeTitles = new[] { "Make Transform", "Construct Transform", "Compose Transform" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 80), Size = new Float2(150, 80),
Elements = new[] Elements = new[]
@@ -446,7 +441,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 25, TypeID = 25,
Title = "Pack Box", Title = "Pack Box",
Description = "Pack components to BoundingBox", Description = "Pack components to BoundingBox",
AlternativeTitles = new[] { "Make Box", "Construct Box", "Compose Box" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 40), Size = new Float2(150, 40),
Elements = new[] Elements = new[]
@@ -460,7 +454,6 @@ namespace FlaxEditor.Surface.Archetypes
{ {
TypeID = 26, TypeID = 26,
Title = "Pack Structure", Title = "Pack Structure",
AlternativeTitles = new[] { "Make Structure", "Construct Structure", "Compose Structure" },
Create = (id, context, arch, groupArch) => new PackStructureNode(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new PackStructureNode(id, context, arch, groupArch),
IsInputCompatible = PackStructureNode.IsInputCompatible, IsInputCompatible = PackStructureNode.IsInputCompatible,
IsOutputCompatible = PackStructureNode.IsOutputCompatible, IsOutputCompatible = PackStructureNode.IsOutputCompatible,
@@ -486,7 +479,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 30, TypeID = 30,
Title = "Unpack Float2", Title = "Unpack Float2",
Description = "Unpack components from Float2", Description = "Unpack components from Float2",
AlternativeTitles = new[] { "Break Float2", "Deconstruct Float2", "Decompose Float2", "Split Float2" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 40), Size = new Float2(150, 40),
Elements = new[] Elements = new[]
@@ -501,7 +493,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 31, TypeID = 31,
Title = "Unpack Float3", Title = "Unpack Float3",
Description = "Unpack components from Float3", Description = "Unpack components from Float3",
AlternativeTitles = new[] { "Break Float3", "Deconstruct Float3", "Decompose Float3", "Split Float3" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 60), Size = new Float2(150, 60),
Elements = new[] Elements = new[]
@@ -517,7 +508,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 32, TypeID = 32,
Title = "Unpack Float4", Title = "Unpack Float4",
Description = "Unpack components from Float4", Description = "Unpack components from Float4",
AlternativeTitles = new[] { "Break Float4", "Deconstruct Float4", "Decompose Float4", "Split Float4" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(150, 80), Size = new Float2(150, 80),
Elements = new[] Elements = new[]
@@ -534,7 +524,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 33, TypeID = 33,
Title = "Unpack Rotation", Title = "Unpack Rotation",
Description = "Unpack components from Rotation", Description = "Unpack components from Rotation",
AlternativeTitles = new[] { "Break Rotation", "Deconstruct Rotation", "Decompose Rotation", "Split Rotation" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(170, 60), Size = new Float2(170, 60),
Elements = new[] Elements = new[]
@@ -550,7 +539,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 34, TypeID = 34,
Title = "Unpack Transform", Title = "Unpack Transform",
Description = "Unpack components from Transform", Description = "Unpack components from Transform",
AlternativeTitles = new[] { "Break Transform", "Deconstruct Transform", "Decompose Transform", "Split Transform" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(170, 60), Size = new Float2(170, 60),
Elements = new[] Elements = new[]
@@ -566,7 +554,6 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 35, TypeID = 35,
Title = "Unpack Box", Title = "Unpack Box",
Description = "Unpack components from BoundingBox", Description = "Unpack components from BoundingBox",
AlternativeTitles = new[] { "Break BoundingBox", "Deconstruct BoundingBox", "Decompose BoundingBox", "Split BoundingBox" },
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(170, 40), Size = new Float2(170, 40),
Elements = new[] Elements = new[]
@@ -585,7 +572,6 @@ namespace FlaxEditor.Surface.Archetypes
IsOutputCompatible = UnpackStructureNode.IsOutputCompatible, IsOutputCompatible = UnpackStructureNode.IsOutputCompatible,
GetInputOutputDescription = UnpackStructureNode.GetInputOutputDescription, GetInputOutputDescription = UnpackStructureNode.GetInputOutputDescription,
Description = "Breaks the structure data to allow extracting components from it.", Description = "Breaks the structure data to allow extracting components from it.",
AlternativeTitles = new[] { "Break Structure", "Deconstruct Structure", "Decompose Structure", "Split Structure" },
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI,
Size = new Float2(180, 20), Size = new Float2(180, 20),
DefaultValues = new object[] DefaultValues = new object[]

View File

@@ -13,7 +13,6 @@ using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
using FlaxEditor.Surface.Undo;
namespace FlaxEditor.Surface.Archetypes namespace FlaxEditor.Surface.Archetypes
{ {
@@ -23,107 +22,15 @@ namespace FlaxEditor.Surface.Archetypes
[HideInEditor] [HideInEditor]
public static class Parameters public static class Parameters
{ {
/// <summary>
/// Surface node type for parameters group Get/Set nodes.
/// </summary>
/// <seealso cref="FlaxEditor.Surface.SurfaceNode" />
public abstract class SurfaceNodeParamsBase : SurfaceNode
{
/// <summary>
/// The combobox for picking parameter.
/// </summary>
protected ComboBoxElement _combobox;
/// <summary>
/// Fag used to block layout updated when updating node.
/// </summary>
protected bool _isUpdateLocked;
/// <inheritdoc />
protected SurfaceNodeParamsBase(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch)
{
}
/// <summary>
/// Gets the selected parameter.
/// </summary>
/// <returns>Surface parameter object or null if nothing selected or cannot find it.</returns>
protected SurfaceParameter GetSelected()
{
if (Surface != null)
return Surface.GetParameter(_combobox.SelectedItem);
return Context.GetParameter((Guid)Values[0]);
}
/// <summary>
/// Updates the combo box.
/// </summary>
protected void UpdateCombo()
{
if (_isUpdateLocked)
return;
_isUpdateLocked = true;
if (_combobox == null)
{
_combobox = GetChild<ComboBoxElement>();
_combobox.SelectedIndexChanged += OnSelectedChanged;
}
string toSelect = null;
Guid loadedSelected = (Guid)Values[0];
_combobox.ClearItems();
var parameters = Surface.Parameters;
for (int i = 0; i < parameters.Count; i++)
{
var param = parameters[i];
if (!param.IsPublic && !Surface.CanShowPrivateParameters)
continue;
_combobox.AddItem(param.Name);
if (param.ID == loadedSelected)
toSelect = param.Name;
}
_combobox.SelectedItem = toSelect;
_isUpdateLocked = false;
}
private void OnSelectedChanged(ComboBox cb)
{
if (_isUpdateLocked)
return;
var selected = GetSelected();
var selectedID = selected?.ID ?? Guid.Empty;
if (selectedID != (Guid)Values[0])
{
if (Surface.Undo != null && Surface.Undo.Enabled)
{
// Capture node connections to support undo
var action = new EditNodeConnections(Context, this);
RemoveConnections();
action.End();
Surface.AddBatchedUndoAction(action);
}
Set(selected, ref selectedID);
}
}
/// <summary>
/// Sets the selected parameter.
/// </summary>
/// <param name="selected">Parameter.</param>
/// <param name="selectedID">Parameter identifier.</param>
protected virtual void Set(SurfaceParameter selected, ref Guid selectedID)
{
SetValue(0, selectedID);
}
}
/// <summary> /// <summary>
/// Surface node type for parameters group Get node. /// Surface node type for parameters group Get node.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Surface.SurfaceNode" /> /// <seealso cref="FlaxEditor.Surface.SurfaceNode" />
public class SurfaceNodeParamsGet : SurfaceNodeParamsBase, IParametersDependantNode public class SurfaceNodeParamsGet : SurfaceNode, IParametersDependantNode
{ {
private ComboBoxElement _combobox;
private readonly List<ISurfaceNodeElement> _dynamicChildren = new List<ISurfaceNodeElement>(); private readonly List<ISurfaceNodeElement> _dynamicChildren = new List<ISurfaceNodeElement>();
private bool _isUpdateLocked;
private ScriptType _layoutType; private ScriptType _layoutType;
private NodeElementArchetype[] _layoutElements; private NodeElementArchetype[] _layoutElements;
@@ -399,6 +306,49 @@ namespace FlaxEditor.Surface.Archetypes
UpdateTitle(); UpdateTitle();
} }
private void UpdateCombo()
{
if (_isUpdateLocked)
return;
_isUpdateLocked = true;
if (_combobox == null)
{
_combobox = (ComboBoxElement)_children[0];
_combobox.SelectedIndexChanged += OnSelectedChanged;
}
int toSelect = -1;
Guid loadedSelected = (Guid)Values[0];
_combobox.ClearItems();
for (int i = 0; i < Surface.Parameters.Count; i++)
{
var param = Surface.Parameters[i];
_combobox.AddItem(param.Name);
if (param.ID == loadedSelected)
toSelect = i;
}
_combobox.SelectedIndex = toSelect;
_isUpdateLocked = false;
}
private void OnSelectedChanged(ComboBox cb)
{
if (_isUpdateLocked)
return;
var selected = GetSelected();
var selectedID = selected?.ID ?? Guid.Empty;
SetValue(0, selectedID);
}
private SurfaceParameter GetSelected()
{
if (Surface != null)
{
var selectedIndex = _combobox.SelectedIndex;
return selectedIndex >= 0 && selectedIndex < Surface.Parameters.Count ? Surface.Parameters[selectedIndex] : null;
}
return Context.GetParameter((Guid)Values[0]);
}
private void ClearDynamicElements() private void ClearDynamicElements()
{ {
for (int i = 0; i < _dynamicChildren.Count; i++) for (int i = 0; i < _dynamicChildren.Count; i++)
@@ -513,19 +463,15 @@ namespace FlaxEditor.Surface.Archetypes
else if (!_isUpdateLocked) else if (!_isUpdateLocked)
{ {
_isUpdateLocked = true; _isUpdateLocked = true;
string toSelect = null; int toSelect = -1;
Guid loadedSelected = (Guid)Values[0]; Guid loadedSelected = (Guid)Values[0];
var parameters = Surface.Parameters; for (int i = 0; i < Surface.Parameters.Count; i++)
for (int i = 0; i < parameters.Count; i++)
{ {
var param = parameters[i]; var param = Surface.Parameters[i];
if (param.ID == loadedSelected) if (param.ID == loadedSelected)
{ toSelect = i;
toSelect = param.Name;
break;
}
} }
_combobox.SelectedItem = toSelect; _combobox.SelectedIndex = toSelect;
_isUpdateLocked = false; _isUpdateLocked = false;
} }
UpdateLayout(); UpdateLayout();
@@ -871,23 +817,66 @@ namespace FlaxEditor.Surface.Archetypes
/// Surface node type for parameters group Set node. /// Surface node type for parameters group Set node.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Surface.SurfaceNode" /> /// <seealso cref="FlaxEditor.Surface.SurfaceNode" />
public class SurfaceNodeParamsSet : SurfaceNodeParamsBase, IParametersDependantNode public class SurfaceNodeParamsSet : SurfaceNode, IParametersDependantNode
{ {
private ComboBoxElement _combobox;
private bool _isUpdateLocked;
/// <inheritdoc /> /// <inheritdoc />
public SurfaceNodeParamsSet(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) public SurfaceNodeParamsSet(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch) : base(id, context, nodeArch, groupArch)
{ {
} }
/// <inheritdoc /> private void UpdateCombo()
protected override void Set(SurfaceParameter selected, ref Guid selectedID)
{ {
SetValues(new[] if (_isUpdateLocked)
return;
_isUpdateLocked = true;
if (_combobox == null)
{ {
selectedID, _combobox = GetChild<ComboBoxElement>();
selected != null ? TypeUtils.GetDefaultValue(selected.Type) : null, _combobox.SelectedIndexChanged += OnSelectedChanged;
}); }
UpdateUI(); int toSelect = -1;
Guid loadedSelected = (Guid)Values[0];
_combobox.ClearItems();
for (int i = 0; i < Surface.Parameters.Count; i++)
{
var param = Surface.Parameters[i];
_combobox.AddItem(param.Name);
if (param.ID == loadedSelected)
toSelect = i;
}
_combobox.SelectedIndex = toSelect;
_isUpdateLocked = false;
}
private void OnSelectedChanged(ComboBox cb)
{
if (_isUpdateLocked)
return;
var selected = GetSelected();
var selectedID = selected?.ID ?? Guid.Empty;
if (selectedID != (Guid)Values[0])
{
SetValues(new[]
{
selectedID,
selected != null ? TypeUtils.GetDefaultValue(selected.Type) : null,
});
UpdateUI();
}
}
private SurfaceParameter GetSelected()
{
if (Surface != null)
{
var selectedIndex = _combobox.SelectedIndex;
return selectedIndex >= 0 && selectedIndex < Surface.Parameters.Count ? Surface.Parameters[selectedIndex] : null;
}
return Context.GetParameter((Guid)Values[0]);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.Surface.Archetypes
Render2D.DrawRectangle(new Rectangle(1, 0, Width - 2, Height - 1), Colors[idx]); Render2D.DrawRectangle(new Rectangle(1, 0, Width - 2, Height - 1), Colors[idx]);
// Close button // Close button
DrawCloseButton(_closeButtonRect, _closeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey);
// Arrange button // Arrange button
var dragBarColor = _arrangeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey; var dragBarColor = _arrangeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey;
@@ -138,12 +138,6 @@ namespace FlaxEditor.Surface.Archetypes
} }
} }
/// <inheritdoc />
public override void Resize(float width, float height)
{
// Do nothing so module does not change size
}
private bool ArrangeAreaCheck(out int index, out Rectangle rect) private bool ArrangeAreaCheck(out int index, out Rectangle rect)
{ {
var barSidesExtend = 20.0f; var barSidesExtend = 20.0f;
@@ -267,9 +261,9 @@ namespace FlaxEditor.Surface.Archetypes
const float closeButtonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin; const float closeButtonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin;
const float closeButtonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize; const float closeButtonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize;
_headerRect = new Rectangle(0, 0, Width, headerSize); _headerRect = new Rectangle(0, 0, Width, headerSize);
_closeButtonRect = new Rectangle(Width - closeButtonSize * 0.75f - closeButtonMargin, closeButtonMargin + 0.25f, closeButtonSize * 0.75f, closeButtonSize * 0.75f); _closeButtonRect = new Rectangle(Width - closeButtonSize - closeButtonMargin, closeButtonMargin, closeButtonSize, closeButtonSize);
_footerRect = Rectangle.Empty; _footerRect = Rectangle.Empty;
_enabled.Location = new Float2(_closeButtonRect.X - _enabled.Width - 2, _closeButtonRect.Y - 0.25f); _enabled.Location = new Float2(_closeButtonRect.X - _enabled.Width - 2, _closeButtonRect.Y);
_arrangeButtonRect = new Rectangle(_enabled.X - closeButtonSize - closeButtonMargin, closeButtonMargin, closeButtonSize, closeButtonSize); _arrangeButtonRect = new Rectangle(_enabled.X - closeButtonSize - closeButtonMargin, closeButtonMargin, closeButtonSize, closeButtonSize);
} }
@@ -467,7 +461,7 @@ namespace FlaxEditor.Surface.Archetypes
/// <summary> /// <summary>
/// The particle module node elements offset applied to controls to reduce default surface node header thickness. /// The particle module node elements offset applied to controls to reduce default surface node header thickness.
/// </summary> /// </summary>
private const float NodeElementsOffset = 16.0f - Surface.Constants.NodeHeaderHeight; private const float NodeElementsOffset = 16.0f - Surface.Constants.NodeHeaderSize;
private const NodeFlags DefaultModuleFlags = NodeFlags.ParticleEmitterGraph | NodeFlags.NoSpawnViaGUI | NodeFlags.NoMove; private const NodeFlags DefaultModuleFlags = NodeFlags.ParticleEmitterGraph | NodeFlags.NoSpawnViaGUI | NodeFlags.NoMove;

View File

@@ -74,7 +74,7 @@ namespace FlaxEditor.Surface.Archetypes
/// <summary> /// <summary>
/// The header height. /// The header height.
/// </summary> /// </summary>
public const float HeaderHeight = FlaxEditor.Surface.Constants.NodeHeaderHeight; public const float HeaderHeight = FlaxEditor.Surface.Constants.NodeHeaderSize;
/// <summary> /// <summary>
/// Gets the type of the module. /// Gets the type of the module.
@@ -199,7 +199,7 @@ namespace FlaxEditor.Surface.Archetypes
DrawChildren(); DrawChildren();
// Options border // Options border
var optionsAreaStart = FlaxEditor.Surface.Constants.NodeHeaderHeight + 3.0f; var optionsAreaStart = FlaxEditor.Surface.Constants.NodeHeaderSize + 3.0f;
var optionsAreaHeight = 7 * FlaxEditor.Surface.Constants.LayoutOffsetY + 6.0f; var optionsAreaHeight = 7 * FlaxEditor.Surface.Constants.LayoutOffsetY + 6.0f;
Render2D.DrawRectangle(new Rectangle(1, optionsAreaStart, Width - 2, optionsAreaHeight), style.BackgroundSelected); Render2D.DrawRectangle(new Rectangle(1, optionsAreaStart, Width - 2, optionsAreaHeight), style.BackgroundSelected);
@@ -340,7 +340,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new ParticleEmitterNode(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new ParticleEmitterNode(id, context, arch, groupArch),
Title = "Particle Emitter", Title = "Particle Emitter",
Description = "Main particle emitter node. Contains a set of modules per emitter context. Modules are executed in order from top to bottom of the stack.", Description = "Main particle emitter node. Contains a set of modules per emitter context. Modules are executed in order from top to bottom of the stack.",
Flags = NodeFlags.ParticleEmitterGraph | NodeFlags.NoRemove | NodeFlags.NoSpawnViaGUI | NodeFlags.NoSpawnViaPaste | NodeFlags.NoCloseButton | NodeFlags.FixedSize, Flags = NodeFlags.ParticleEmitterGraph | NodeFlags.NoRemove | NodeFlags.NoSpawnViaGUI | NodeFlags.NoSpawnViaPaste | NodeFlags.NoCloseButton,
Size = new Float2(300, 600), Size = new Float2(300, 600),
DefaultValues = new object[] DefaultValues = new object[]
{ {

View File

@@ -57,7 +57,7 @@ namespace FlaxEditor.Surface.Archetypes
{ {
_textureGroupPicker = new ComboBox _textureGroupPicker = new ComboBox
{ {
Location = new Float2(FlaxEditor.Surface.Constants.NodeMarginX + 50, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight + FlaxEditor.Surface.Constants.LayoutOffsetY * _level), Location = new Float2(FlaxEditor.Surface.Constants.NodeMarginX + 50, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize + FlaxEditor.Surface.Constants.LayoutOffsetY * _level),
Width = 100, Width = 100,
Parent = this, Parent = this,
}; };
@@ -133,8 +133,8 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Texture", Title = "Texture",
Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))),
Description = "Two dimensional texture object", Description = "Two dimensional texture object",
Flags = NodeFlags.MaterialGraph | NodeFlags.FixedSize, Flags = NodeFlags.MaterialGraph,
Size = new Float2(140, 140), Size = new Float2(140, 120),
DefaultValues = new object[] DefaultValues = new object[]
{ {
Guid.Empty Guid.Empty
@@ -158,7 +158,7 @@ namespace FlaxEditor.Surface.Archetypes
AlternativeTitles = new string[] { "UV", "UVs" }, AlternativeTitles = new string[] { "UV", "UVs" },
Description = "Texture coordinates", Description = "Texture coordinates",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(160, 20), Size = new Float2(150, 30),
DefaultValues = new object[] DefaultValues = new object[]
{ {
0u 0u
@@ -176,8 +176,8 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Cube Texture", Title = "Cube Texture",
Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))),
Description = "Set of 6 textures arranged in a cube", Description = "Set of 6 textures arranged in a cube",
Flags = NodeFlags.MaterialGraph | NodeFlags.FixedSize, Flags = NodeFlags.MaterialGraph,
Size = new Float2(140, 140), Size = new Float2(140, 120),
DefaultValues = new object[] DefaultValues = new object[]
{ {
Guid.Empty Guid.Empty
@@ -239,7 +239,7 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(3, "Max Steps", true, typeof(float), 3, 2), NodeElementArchetype.Factory.Input(3, "Max Steps", true, typeof(float), 3, 2),
NodeElementArchetype.Factory.Input(4, "Heightmap Texture", true, typeof(FlaxEngine.Object), 4), NodeElementArchetype.Factory.Input(4, "Heightmap Texture", true, typeof(FlaxEngine.Object), 4),
NodeElementArchetype.Factory.Output(0, "Parallax UVs", typeof(Float2), 5), NodeElementArchetype.Factory.Output(0, "Parallax UVs", typeof(Float2), 5),
NodeElementArchetype.Factory.Text(Surface.Constants.BoxRowHeight + 4, 5 * Surface.Constants.LayoutOffsetY, "Channel"), NodeElementArchetype.Factory.Text(Surface.Constants.BoxSize + 4, 5 * Surface.Constants.LayoutOffsetY, "Channel"),
NodeElementArchetype.Factory.ComboBox(70, 5 * Surface.Constants.LayoutOffsetY, 50, 3, new[] NodeElementArchetype.Factory.ComboBox(70, 5 * Surface.Constants.LayoutOffsetY, 50, 3, new[]
{ {
"R", "R",
@@ -493,7 +493,7 @@ namespace FlaxEditor.Surface.Archetypes
{ {
TypeID = 18, TypeID = 18,
Title = "Lightmap UV", Title = "Lightmap UV",
AlternativeTitles = new string[] { "Lightmap TexCoord" }, AlternativeTitles = new string[] { "Lightmap TexCoord" },
Description = "Lightmap UVs", Description = "Lightmap UVs",
Flags = NodeFlags.MaterialGraph, Flags = NodeFlags.MaterialGraph,
Size = new Float2(110, 20), Size = new Float2(110, 20),

View File

@@ -467,7 +467,7 @@ namespace FlaxEditor.Surface.Archetypes
Create = (id, context, arch, groupArch) => new CurveNode<T>(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new CurveNode<T>(id, context, arch, groupArch),
Description = "An animation spline represented by a set of keyframes, each representing an endpoint of a Bezier curve.", Description = "An animation spline represented by a set of keyframes, each representing an endpoint of a Bezier curve.",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(400, 180.0f), Size = new Float2(400, 180),
DefaultValues = new object[] DefaultValues = new object[]
{ {
// Keyframes count // Keyframes count
@@ -485,7 +485,7 @@ namespace FlaxEditor.Surface.Archetypes
zero, // Tangent In zero, // Tangent In
zero, // Tangent Out zero, // Tangent Out
// Empty keys 0-6 // Empty keys zero-6
0.0f, zero, zero, zero, 0.0f, zero, zero, zero,
0.0f, zero, zero, zero, 0.0f, zero, zero, zero,
0.0f, zero, zero, zero, 0.0f, zero, zero, zero,
@@ -515,12 +515,13 @@ namespace FlaxEditor.Surface.Archetypes
base.OnLoaded(action); base.OnLoaded(action);
// Create curve editor // Create curve editor
var upperLeft = GetBox(0).BottomRight; var upperLeft = GetBox(0).BottomLeft;
var upperRight = GetBox(1).BottomLeft; var upperRight = GetBox(1).BottomRight;
float curveMargin = 20.0f;
_curve = new BezierCurveEditor<T> _curve = new BezierCurveEditor<T>
{ {
MaxKeyframes = 7, MaxKeyframes = 7,
Bounds = new Rectangle(upperLeft + new Float2(0f, 10.0f), upperRight.X - upperLeft.X - 8.0f, 135.0f), Bounds = new Rectangle(upperLeft + new Float2(curveMargin, 10.0f), upperRight.X - upperLeft.X - curveMargin * 2.0f, 140.0f),
Parent = this, Parent = this,
AnchorMax = Float2.One, AnchorMax = Float2.One,
}; };
@@ -840,7 +841,7 @@ namespace FlaxEditor.Surface.Archetypes
_picker = new TypePickerControl _picker = new TypePickerControl
{ {
Type = ScriptType.FlaxObject, Type = ScriptType.FlaxObject,
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName); _picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName);
@@ -909,7 +910,7 @@ namespace FlaxEditor.Surface.Archetypes
_picker = new TypePickerControl _picker = new TypePickerControl
{ {
Type = ScriptType.Object, Type = ScriptType.Object,
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 140, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 140, 16),
Parent = this, Parent = this,
}; };
_picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName); _picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName);
@@ -960,7 +961,7 @@ namespace FlaxEditor.Surface.Archetypes
_picker = new TypePickerControl _picker = new TypePickerControl
{ {
Type = ScriptType.FlaxObject, Type = ScriptType.FlaxObject,
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName); _picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName);
@@ -1011,7 +1012,7 @@ namespace FlaxEditor.Surface.Archetypes
_picker = new TypePickerControl _picker = new TypePickerControl
{ {
Type = type, Type = type,
Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderHeight, 160, 16), Bounds = new Rectangle(FlaxEditor.Surface.Constants.NodeMarginX + 20, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize, 160, 16),
Parent = this, Parent = this,
}; };
_picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName); _picker.ValueChanged += () => SetValue(0, _picker.ValueTypeName);
@@ -1070,11 +1071,7 @@ namespace FlaxEditor.Surface.Archetypes
internal class RerouteNode : SurfaceNode, IConnectionInstigator internal class RerouteNode : SurfaceNode, IConnectionInstigator
{ {
internal static readonly Float2 DefaultSize = new Float2(FlaxEditor.Surface.Constants.BoxRowHeight); internal static readonly Float2 DefaultSize = new Float2(FlaxEditor.Surface.Constants.BoxSize);
internal bool DrawDisabled => _input.AllConnectionsDisabled || _output.AllConnectionsDisabled;
internal override bool DrawBasicShadow => false;
private Rectangle _localBounds; private Rectangle _localBounds;
private InputBox _input; private InputBox _input;
private OutputBox _output; private OutputBox _output;
@@ -1177,18 +1174,9 @@ namespace FlaxEditor.Surface.Archetypes
_footerRect = Rectangle.Empty; _footerRect = Rectangle.Empty;
} }
/// <inheritdoc />
public override void Resize(float width, float height)
{
// Do nothing so the input and output boxes do not change position
}
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {
// Update active state of input
_input.IsActive = !_output.AllConnectionsDisabled;
var style = Surface.Style; var style = Surface.Style;
var connectionColor = style.Colors.Default; var connectionColor = style.Colors.Default;
var type = ScriptType.Null; var type = ScriptType.Null;
@@ -1202,10 +1190,6 @@ namespace FlaxEditor.Surface.Archetypes
Surface.Style.GetConnectionColor(type, hints, out connectionColor); Surface.Style.GetConnectionColor(type, hints, out connectionColor);
} }
// Draw the box as disabled if needed
if (DrawDisabled)
connectionColor = connectionColor * 0.6f;
if (!_input.HasAnyConnection) if (!_input.HasAnyConnection)
Render2D.FillRectangle(new Rectangle(-barHorizontalOffset - barHeight * 2, (DefaultSize.Y - barHeight) / 2, barHeight * 2, barHeight), connectionColor); Render2D.FillRectangle(new Rectangle(-barHorizontalOffset - barHeight * 2, (DefaultSize.Y - barHeight) / 2, barHeight * 2, barHeight), connectionColor);
if (!_output.HasAnyConnection) if (!_output.HasAnyConnection)
@@ -1216,11 +1200,6 @@ namespace FlaxEditor.Surface.Archetypes
icon = type.IsVoid ? style.Icons.ArrowClose : style.Icons.BoxClose; icon = type.IsVoid ? style.Icons.ArrowClose : style.Icons.BoxClose;
else else
icon = type.IsVoid ? style.Icons.ArrowOpen : style.Icons.BoxOpen; icon = type.IsVoid ? style.Icons.ArrowOpen : style.Icons.BoxOpen;
// Shadow
var shadowRect = _localBounds.MakeOffsetted(ShadowOffset);
Render2D.DrawSprite(icon, shadowRect, Color.Black.AlphaMultiplied(0.125f));
Render2D.DrawSprite(icon, _localBounds, connectionColor); Render2D.DrawSprite(icon, _localBounds, connectionColor);
base.Draw(); base.Draw();
@@ -1465,8 +1444,8 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 6, TypeID = 6,
Title = "Panner", Title = "Panner",
Description = "Animates UVs over time", Description = "Animates UVs over time",
Flags = NodeFlags.MaterialGraph | NodeFlags.FixedSize, Flags = NodeFlags.MaterialGraph,
Size = new Float2(170, 96), Size = new Float2(170, 80),
DefaultValues = new object[] DefaultValues = new object[]
{ {
false false
@@ -1476,7 +1455,7 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0), NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
NodeElementArchetype.Factory.Input(1, "Time", true, typeof(float), 1), NodeElementArchetype.Factory.Input(1, "Time", true, typeof(float), 1),
NodeElementArchetype.Factory.Input(2, "Speed", true, typeof(Float2), 2), NodeElementArchetype.Factory.Input(2, "Speed", true, typeof(Float2), 2),
NodeElementArchetype.Factory.Text(20, Surface.Constants.LayoutOffsetY * 3 + 5, "Fractional Part"), NodeElementArchetype.Factory.Text(18, Surface.Constants.LayoutOffsetY * 3 + 5, "Fractional Part"),
NodeElementArchetype.Factory.Bool(0, Surface.Constants.LayoutOffsetY * 3 + 5, 0), NodeElementArchetype.Factory.Bool(0, Surface.Constants.LayoutOffsetY * 3 + 5, 0),
NodeElementArchetype.Factory.Output(0, "", typeof(Float2), 3) NodeElementArchetype.Factory.Output(0, "", typeof(Float2), 3)
} }
@@ -1526,7 +1505,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Color Gradient", Title = "Color Gradient",
Create = (id, context, arch, groupArch) => new ColorGradientNode(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new ColorGradientNode(id, context, arch, groupArch),
Description = "Linear color gradient sampler", Description = "Linear color gradient sampler",
Flags = NodeFlags.AllGraphs | NodeFlags.FixedSize, Flags = NodeFlags.AllGraphs,
Size = new Float2(400, 150.0f), Size = new Float2(400, 150.0f),
DefaultValues = new object[] DefaultValues = new object[]
{ {
@@ -1846,7 +1825,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Reroute", Title = "Reroute",
Create = (id, context, arch, groupArch) => new RerouteNode(id, context, arch, groupArch), Create = (id, context, arch, groupArch) => new RerouteNode(id, context, arch, groupArch),
Description = "Reroute a connection.", Description = "Reroute a connection.",
Flags = NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaGUI | NodeFlags.AllGraphs | NodeFlags.FixedSize, Flags = NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaGUI | NodeFlags.AllGraphs,
Size = RerouteNode.DefaultSize, Size = RerouteNode.DefaultSize,
ConnectionsHints = ConnectionsHint.All, ConnectionsHints = ConnectionsHint.All,
IndependentBoxes = new int[] { 0 }, IndependentBoxes = new int[] { 0 },

View File

@@ -13,61 +13,46 @@ namespace FlaxEditor.Surface
/// <summary> /// <summary>
/// The node close button size. /// The node close button size.
/// </summary> /// </summary>
public const float NodeCloseButtonSize = 10.0f; public const float NodeCloseButtonSize = 12.0f;
/// <summary> /// <summary>
/// The node close button margin from the edges. /// The node close button margin from the edges.
/// </summary> /// </summary>
public const float NodeCloseButtonMargin = 5.0f; public const float NodeCloseButtonMargin = 2.0f;
/// <summary> /// <summary>
/// The node header height. /// The node header height.
/// </summary> /// </summary>
public const float NodeHeaderHeight = 25.0f; public const float NodeHeaderSize = 28.0f;
/// <summary>
/// The scale of the header text.
/// </summary>
public const float NodeHeaderTextScale = 0.8f;
/// <summary> /// <summary>
/// The node footer height. /// The node footer height.
/// </summary> /// </summary>
public const float NodeFooterSize = 2.0f; public const float NodeFooterSize = 4.0f;
/// <summary> /// <summary>
/// The horizontal node margin. /// The node left margin.
/// </summary> /// </summary>
public const float NodeMarginX = 6.0f; public const float NodeMarginX = 5.0f;
/// <summary> /// <summary>
/// The vertical node right margin. /// The node right margin.
/// </summary> /// </summary>
public const float NodeMarginY = 8.0f; public const float NodeMarginY = 5.0f;
/// <summary> /// <summary>
/// The size of the row that is started by a box. /// The box position offset on the x axis.
/// </summary> /// </summary>
public const float BoxRowHeight = 19.0f; public const float BoxOffsetX = 2.0f;
/// <summary> /// <summary>
/// The box size (with and height). /// The box size (with and height).
/// </summary> /// </summary>
public const float BoxSize = 15.0f; public const float BoxSize = 20.0f;
/// <summary> /// <summary>
/// The node layout offset on the y axis (height of the boxes rows, etc.). It's used to make the design more consistent. /// The node layout offset on the y axis (height of the boxes rows, etc.). It's used to make the design more consistent.
/// </summary> /// </summary>
public const float LayoutOffsetY = 24.0f; public const float LayoutOffsetY = 20.0f;
/// <summary>
/// The offset between the box text and the box
/// </summary>
public const float BoxTextOffset = 1.65f;
/// <summary>
/// The width of the rectangle used to draw the box text.
/// </summary>
public const float BoxTextRectWidth = 500.0f;
} }
} }

View File

@@ -585,7 +585,7 @@ namespace FlaxEditor.Surface.ContextMenu
private void UpdateFilters() private void UpdateFilters()
{ {
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes.Count == 0) if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes[0] == null)
{ {
ResetView(); ResetView();
Profiler.EndEvent(); Profiler.EndEvent();

View File

@@ -33,7 +33,7 @@ namespace FlaxEditor.Surface.Elements
/// <inheritdoc /> /// <inheritdoc />
public BoolValue(SurfaceNode parentNode, NodeElementArchetype archetype) public BoolValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype, archetype.ActualPosition, new Float2(Constants.BoxRowHeight), true) : base(parentNode, archetype, archetype.ActualPosition, new Float2(16), true)
{ {
} }

View File

@@ -2,7 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Undo; using FlaxEditor.Surface.Undo;
using FlaxEngine; using FlaxEngine;
@@ -195,19 +194,9 @@ namespace FlaxEditor.Surface.Elements
set => _isActive = value; set => _isActive = value;
} }
/// <summary>
/// Gets if the box is disabled (user can still connect, but connections will be ignored).
/// </summary>
public bool IsDisabled => !(Enabled && IsActive);
/// <summary>
/// Gets a value indicating whether all connections are disabled.
/// </summary>
public bool AllConnectionsDisabled => Connections.All(c => c.IsDisabled);
/// <inheritdoc /> /// <inheritdoc />
protected Box(SurfaceNode parentNode, NodeElementArchetype archetype, Float2 location) protected Box(SurfaceNode parentNode, NodeElementArchetype archetype, Float2 location)
: base(parentNode, archetype, location, new Float2(Constants.BoxRowHeight), false) : base(parentNode, archetype, location, new Float2(Constants.BoxSize), false)
{ {
_currentType = DefaultType; _currentType = DefaultType;
_isSingle = Archetype.Single; _isSingle = Archetype.Single;
@@ -363,10 +352,10 @@ namespace FlaxEditor.Surface.Elements
Assert.AreEqual(r1, r2); Assert.AreEqual(r1, r2);
// Update // Update
OnConnectionsChanged();
box.OnConnectionsChanged();
ConnectionTick(); ConnectionTick();
box.ConnectionTick(); box.ConnectionTick();
OnConnectionsChanged();
box.OnConnectionsChanged();
Surface?.OnNodesDisconnected(this, box); Surface?.OnNodesDisconnected(this, box);
} }
@@ -390,10 +379,10 @@ namespace FlaxEditor.Surface.Elements
Assert.IsTrue(AreConnected(box)); Assert.IsTrue(AreConnected(box));
// Update // Update
OnConnectionsChanged();
box.OnConnectionsChanged();
ConnectionTick(); ConnectionTick();
box.ConnectionTick(); box.ConnectionTick();
OnConnectionsChanged();
box.OnConnectionsChanged();
Surface?.OnNodesConnected(this, box); Surface?.OnNodesConnected(this, box);
} }

View File

@@ -28,7 +28,6 @@ namespace FlaxEditor.Surface.Elements
public ColorValue(SurfaceNode parentNode, NodeElementArchetype archetype) public ColorValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y) : base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y)
{ {
Height = Constants.BoxRowHeight;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;
UseDynamicEditing = false; UseDynamicEditing = false;

View File

@@ -33,7 +33,6 @@ namespace FlaxEditor.Surface.Elements
public ComboBoxElement(SurfaceNode parentNode, NodeElementArchetype archetype) public ComboBoxElement(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(archetype.ActualPositionX, archetype.ActualPositionY, archetype.Size.X) : base(archetype.ActualPositionX, archetype.ActualPositionY, archetype.Size.X)
{ {
Height = Constants.BoxRowHeight;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;

View File

@@ -2,7 +2,6 @@
using System; using System;
using FlaxEditor.GUI; using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.Surface.Elements namespace FlaxEditor.Surface.Elements
@@ -30,7 +29,9 @@ namespace FlaxEditor.Surface.Elements
public EnumValue(SurfaceNode parentNode, NodeElementArchetype archetype) public EnumValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(TypeUtils.GetType(archetype.Text).Type) : base(TypeUtils.GetType(archetype.Text).Type)
{ {
Bounds = new Rectangle(archetype.ActualPositionX, archetype.ActualPositionY, archetype.Size.X, Constants.BoxRowHeight); X = archetype.ActualPositionX;
Y = archetype.ActualPositionY;
Width = archetype.Size.X;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;
Value = Convert.ToInt32(ParentNode.Values[Archetype.ValueIndex]); Value = Convert.ToInt32(ParentNode.Values[Archetype.ValueIndex]);

View File

@@ -29,7 +29,6 @@ namespace FlaxEditor.Surface.Elements
public FloatValue(SurfaceNode parentNode, NodeElementArchetype archetype) public FloatValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, archetype.ValueMin, archetype.ValueMax, 0.01f) : base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, archetype.ValueMin, archetype.ValueMax, 0.01f)
{ {
Height = Constants.BoxRowHeight;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;

View File

@@ -120,7 +120,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = IntegerValue.Get(box.ParentNode, box.Archetype, box.Value); var value = IntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
var width = 50; var width = 40;
var control = new IntValueBox(value, bounds.X, bounds.Y, width + 12, int.MinValue, int.MaxValue, 0.01f) var control = new IntValueBox(value, bounds.X, bounds.Y, width + 12, int.MinValue, int.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -166,7 +166,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype, box.Value); var value = UnsignedIntegerValue.Get(box.ParentNode, box.Archetype, box.Value);
var width = 50; var width = 40;
var control = new UIntValueBox(value, bounds.X, bounds.Y, width + 12, uint.MinValue, uint.MaxValue, 0.01f) var control = new UIntValueBox(value, bounds.X, bounds.Y, width + 12, uint.MinValue, uint.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -212,7 +212,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = FloatValue.Get(box.ParentNode, box.Archetype, box.Value); var value = FloatValue.Get(box.ParentNode, box.Archetype, box.Value);
var width = 50; var width = 40;
var control = new FloatValueBox(value, bounds.X, bounds.Y, width + 12, float.MinValue, float.MaxValue, 0.01f) var control = new FloatValueBox(value, bounds.X, bounds.Y, width + 12, float.MinValue, float.MaxValue, 0.01f)
{ {
Height = bounds.Height, Height = bounds.Height,
@@ -303,7 +303,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -377,7 +377,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -460,7 +460,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 20;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -553,7 +553,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -627,7 +627,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -710,7 +710,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 20;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -803,7 +803,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 2 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -877,7 +877,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 30;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -960,7 +960,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box); var value = GetValue(box);
var width = 50; var width = 20;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 4 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -1053,7 +1053,7 @@ namespace FlaxEditor.Surface.Elements
public Control Create(InputBox box, ref Rectangle bounds) public Control Create(InputBox box, ref Rectangle bounds)
{ {
var value = GetValue(box).EulerAngles; var value = GetValue(box).EulerAngles;
var width = 50; var width = 20;
var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height) var control = new ContainerControl(bounds.X, bounds.Y, (width + 2) * 3 - 2, bounds.Height)
{ {
ClipChildren = false, ClipChildren = false,
@@ -1442,8 +1442,8 @@ namespace FlaxEditor.Surface.Elements
// Draw text // Draw text
var style = Style.Current; var style = Style.Current;
var rect = new Rectangle(Width + Constants.BoxTextOffset, 0, Constants.BoxTextRectWidth, Height); var rect = new Rectangle(Width + 4, 0, 1410, Height);
Render2D.DrawText(style.FontMedium, Text, rect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontSmall, Text, rect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Near, TextAlignment.Center);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -32,7 +32,6 @@ namespace FlaxEditor.Surface.Elements
public IntegerValue(SurfaceNode parentNode, NodeElementArchetype archetype) public IntegerValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, (int)archetype.ValueMin, (int)archetype.ValueMax, 0.05f) : base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, (int)archetype.ValueMin, (int)archetype.ValueMax, 0.05f)
{ {
Height = Constants.BoxRowHeight;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;

View File

@@ -34,6 +34,11 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
public const float DefaultConnectionOffset = 24f; public const float DefaultConnectionOffset = 24f;
/// <summary>
/// Distance for the mouse to be considered above the connection
/// </summary>
public float MouseOverConnectionDistance => 100f / Surface.ViewScale;
/// <inheritdoc /> /// <inheritdoc />
public OutputBox(SurfaceNode parentNode, NodeElementArchetype archetype) public OutputBox(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype, archetype.Position + new Float2(parentNode.Archetype.Size.X, 0)) : base(parentNode, archetype, archetype.Position + new Float2(parentNode.Archetype.Size.X, 0))
@@ -104,13 +109,12 @@ namespace FlaxEditor.Surface.Elements
/// </summary> /// </summary>
/// <param name="targetBox">The other box.</param> /// <param name="targetBox">The other box.</param>
/// <param name="mousePosition">The mouse position</param> /// <param name="mousePosition">The mouse position</param>
/// <param name="distance">Distance at which its an intersection</param> public bool IntersectsConnection(Box targetBox, ref Float2 mousePosition)
public bool IntersectsConnection(Box targetBox, ref Float2 mousePosition, float distance)
{ {
float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature)); float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature));
Float2 start = new Float2(ConnectionOrigin.X + connectionOffset, ConnectionOrigin.Y); Float2 start = new Float2(ConnectionOrigin.X + connectionOffset, ConnectionOrigin.Y);
Float2 end = new Float2(targetBox.ConnectionOrigin.X - connectionOffset, targetBox.ConnectionOrigin.Y); Float2 end = new Float2(targetBox.ConnectionOrigin.X - connectionOffset, targetBox.ConnectionOrigin.Y);
return IntersectsConnection(ref start, ref end, ref mousePosition, distance); return IntersectsConnection(ref start, ref end, ref mousePosition, MouseOverConnectionDistance);
} }
/// <summary> /// <summary>
@@ -178,7 +182,7 @@ namespace FlaxEditor.Surface.Elements
{ {
// Draw all the connections // Draw all the connections
var style = Surface.Style; var style = Surface.Style;
var mouseOverDistance = Surface.MouseOverConnectionDistance; var mouseOverDistance = MouseOverConnectionDistance;
var startPos = ConnectionOrigin; var startPos = ConnectionOrigin;
var startHighlight = ConnectionsHighlightIntensity; var startHighlight = ConnectionsHighlightIntensity;
for (int i = 0; i < Connections.Count; i++) for (int i = 0; i < Connections.Count; i++)
@@ -186,7 +190,7 @@ namespace FlaxEditor.Surface.Elements
Box targetBox = Connections[i]; Box targetBox = Connections[i];
var endPos = targetBox.ConnectionOrigin; var endPos = targetBox.ConnectionOrigin;
var highlight = DefaultConnectionThickness + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity); var highlight = DefaultConnectionThickness + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity);
var alpha = targetBox.IsDisabled ? 0.6f : 1.0f; var alpha = targetBox.Enabled && targetBox.IsActive ? 1.0f : 0.6f;
// We have to calculate an offset here to preserve the original color for when the default connection thickness is larger than 1 // We have to calculate an offset here to preserve the original color for when the default connection thickness is larger than 1
var highlightOffset = (highlight - (DefaultConnectionThickness - 1)); var highlightOffset = (highlight - (DefaultConnectionThickness - 1));
@@ -212,7 +216,7 @@ namespace FlaxEditor.Surface.Elements
// Draw all the connections // Draw all the connections
var startPos = ConnectionOrigin; var startPos = ConnectionOrigin;
var endPos = targetBox.ConnectionOrigin; var endPos = targetBox.ConnectionOrigin;
var alpha = targetBox.IsDisabled ? 0.6f : 1.0f; var alpha = targetBox.Enabled && targetBox.IsActive ? 1.0f : 0.6f;
var color = _currentTypeColor * alpha; var color = _currentTypeColor * alpha;
DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, SelectedConnectionThickness); DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, SelectedConnectionThickness);
} }
@@ -230,8 +234,8 @@ namespace FlaxEditor.Surface.Elements
// Draw text // Draw text
var style = Style.Current; var style = Style.Current;
var rect = new Rectangle(-Constants.BoxTextRectWidth - Constants.BoxTextOffset * 2f, 0f, Constants.BoxTextRectWidth, Height); var rect = new Rectangle(-100, 0, 100 - 2, Height);
Render2D.DrawText(style.FontMedium, Text, rect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Far, TextAlignment.Center); Render2D.DrawText(style.FontSmall, Text, rect, Enabled ? style.Foreground : style.ForegroundDisabled, TextAlignment.Far, TextAlignment.Center);
} }
} }
} }

View File

@@ -24,7 +24,6 @@ namespace FlaxEditor.Surface.Elements
public UnsignedIntegerValue(SurfaceNode parentNode, NodeElementArchetype archetype) public UnsignedIntegerValue(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, (uint)archetype.ValueMin, (uint)archetype.ValueMax, 0.05f) : base(Get(parentNode, archetype), archetype.Position.X, archetype.Position.Y, 50, (uint)archetype.ValueMin, (uint)archetype.ValueMax, 0.05f)
{ {
Height = Constants.BoxRowHeight;
ParentNode = parentNode; ParentNode = parentNode;
Archetype = archetype; Archetype = archetype;

View File

@@ -3,9 +3,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using FlaxEditor.GUI.Input; using FlaxEditor.CustomEditors;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Surface namespace FlaxEditor.Surface
@@ -79,12 +78,12 @@ namespace FlaxEditor.Surface
/// <summary> /// <summary>
/// Gets the actual element position on the y axis. /// Gets the actual element position on the y axis.
/// </summary> /// </summary>
public float ActualPositionY => Position.Y + Constants.NodeMarginY + Constants.NodeHeaderHeight; public float ActualPositionY => Position.Y + Constants.NodeMarginY + Constants.NodeHeaderSize;
/// <summary> /// <summary>
/// Gets the actual element position. /// Gets the actual element position.
/// </summary> /// </summary>
public Float2 ActualPosition => new Float2(Position.X + Constants.NodeMarginX, Position.Y + Constants.NodeMarginY + Constants.NodeHeaderHeight); public Float2 ActualPosition => new Float2(Position.X + Constants.NodeMarginX, Position.Y + Constants.NodeMarginY + Constants.NodeHeaderSize);
/// <summary> /// <summary>
/// Node element archetypes factory object. Helps to build surface nodes archetypes. /// Node element archetypes factory object. Helps to build surface nodes archetypes.
@@ -107,8 +106,8 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.Input, Type = NodeElementType.Input,
Position = new Float2( Position = new Float2(
Constants.NodeMarginX, Constants.NodeMarginX - Constants.BoxOffsetX,
Constants.NodeMarginY + Constants.NodeHeaderHeight + yLevel * Constants.LayoutOffsetY), Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY),
Text = text, Text = text,
Single = single, Single = single,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -133,8 +132,8 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.Input, Type = NodeElementType.Input,
Position = new Float2( Position = new Float2(
Constants.NodeMarginX, Constants.NodeMarginX - Constants.BoxOffsetX,
Constants.NodeMarginY + Constants.NodeHeaderHeight + yLevel * Constants.LayoutOffsetY), Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY),
Text = text, Text = text,
Single = single, Single = single,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -158,8 +157,8 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.Output, Type = NodeElementType.Output,
Position = new Float2( Position = new Float2(
-Constants.NodeMarginX, Constants.NodeMarginX - Constants.BoxSize + Constants.BoxOffsetX,
Constants.NodeMarginY + Constants.NodeHeaderHeight + yLevel * Constants.LayoutOffsetY), Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY),
Text = text, Text = text,
Single = single, Single = single,
ValueIndex = -1, ValueIndex = -1,
@@ -183,8 +182,8 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.Output, Type = NodeElementType.Output,
Position = new Float2( Position = new Float2(
-Constants.NodeMarginX, Constants.NodeMarginX - Constants.BoxSize + Constants.BoxOffsetX,
Constants.NodeMarginY + Constants.NodeHeaderHeight + yLevel * Constants.LayoutOffsetY), Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY),
Text = text, Text = text,
Single = single, Single = single,
ValueIndex = -1, ValueIndex = -1,
@@ -206,7 +205,6 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.BoolValue, Type = NodeElementType.BoolValue,
Position = new Float2(x, y), Position = new Float2(x, y),
Size = new Float2(16f),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -230,8 +228,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.IntegerValue, Type = NodeElementType.IntegerValue,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Size = new Float2(50f, IntegerValue.DefaultHeight),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -257,8 +254,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.UnsignedIntegerValue, Type = NodeElementType.UnsignedIntegerValue,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Size = new Float2(50f, UnsignedIntegerValue.DefaultHeight),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -284,8 +280,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.FloatValue, Type = NodeElementType.FloatValue,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Size = new Float2(50f, FloatValueBox.DefaultHeight),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -364,8 +359,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.ColorValue, Type = NodeElementType.ColorValue,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Size = new Float2(32, 18),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -388,7 +382,6 @@ namespace FlaxEditor.Surface
{ {
Type = NodeElementType.Asset, Type = NodeElementType.Asset,
Position = new Float2(x, y), Position = new Float2(x, y),
Size = new Float2(78f, 90f),
Text = type.FullName, Text = type.FullName,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -506,7 +499,7 @@ namespace FlaxEditor.Surface
/// <param name="height">The control height.</param> /// <param name="height">The control height.</param>
/// <param name="tooltip">The control tooltip text.</param> /// <param name="tooltip">The control tooltip text.</param>
/// <returns>The archetype.</returns> /// <returns>The archetype.</returns>
public static NodeElementArchetype Text(float x, float y, string text, float width = 100.0f, float height = 19.0f, string tooltip = null) public static NodeElementArchetype Text(float x, float y, string text, float width = 100.0f, float height = 16.0f, string tooltip = null)
{ {
return new NodeElementArchetype return new NodeElementArchetype
{ {
@@ -537,7 +530,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.TextBox, Type = NodeElementType.TextBox,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Size = new Float2(width, height), Size = new Float2(width, height),
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,
@@ -602,7 +595,7 @@ namespace FlaxEditor.Surface
return new NodeElementArchetype return new NodeElementArchetype
{ {
Type = NodeElementType.BoxValue, Type = NodeElementType.BoxValue,
Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderHeight + y), Position = new Float2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
Text = null, Text = null,
Single = false, Single = false,
ValueIndex = valueIndex, ValueIndex = valueIndex,

View File

@@ -60,84 +60,84 @@ namespace FlaxEditor.Surface
{ {
GroupID = 1, GroupID = 1,
Name = "Material", Name = "Material",
Color = new Color(181, 89, 49), Color = new Color(231, 76, 60),
Archetypes = Archetypes.Material.Nodes Archetypes = Archetypes.Material.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 2, GroupID = 2,
Name = "Constants", Name = "Constants",
Color = new Color(163, 106, 21), Color = new Color(243, 156, 18),
Archetypes = Archetypes.Constants.Nodes Archetypes = Archetypes.Constants.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 3, GroupID = 3,
Name = "Math", Name = "Math",
Color = new Color(45, 126, 181), Color = new Color(52, 152, 219),
Archetypes = Archetypes.Math.Nodes Archetypes = Archetypes.Math.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 4, GroupID = 4,
Name = "Packing", Name = "Packing",
Color = new Color(124, 66, 143), Color = new Color(155, 89, 182),
Archetypes = Archetypes.Packing.Nodes Archetypes = Archetypes.Packing.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 5, GroupID = 5,
Name = "Textures", Name = "Textures",
Color = new Color(43, 130, 83), Color = new Color(46, 204, 113),
Archetypes = Archetypes.Textures.Nodes Archetypes = Archetypes.Textures.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 6, GroupID = 6,
Name = "Parameters", Name = "Parameters",
Color = new Color(55, 78, 99), Color = new Color(52, 73, 94),
Archetypes = Archetypes.Parameters.Nodes Archetypes = Archetypes.Parameters.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 7, GroupID = 7,
Name = "Tools", Name = "Tools",
Color = new Color(88, 96, 97), Color = new Color(149, 165, 166),
Archetypes = Archetypes.Tools.Nodes Archetypes = Archetypes.Tools.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 8, GroupID = 8,
Name = "Layers", Name = "Layers",
Color = new Color(189, 75, 81), Color = new Color(249, 105, 116),
Archetypes = Archetypes.Layers.Nodes Archetypes = Archetypes.Layers.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 9, GroupID = 9,
Name = "Animations", Name = "Animations",
Color = new Color(72, 125, 107), Color = new Color(105, 179, 160),
Archetypes = Archetypes.Animation.Nodes Archetypes = Archetypes.Animation.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 10, GroupID = 10,
Name = "Boolean", Name = "Boolean",
Color = new Color(166, 27, 32), Color = new Color(237, 28, 36),
Archetypes = Archetypes.Boolean.Nodes Archetypes = Archetypes.Boolean.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 11, GroupID = 11,
Name = "Bitwise", Name = "Bitwise",
Color = new Color(96, 125, 34), Color = new Color(181, 230, 29),
Archetypes = Archetypes.Bitwise.Nodes Archetypes = Archetypes.Bitwise.Nodes
}, },
new GroupArchetype new GroupArchetype
{ {
GroupID = 12, GroupID = 12,
Name = "Comparisons", Name = "Comparisons",
Color = new Color(166, 33, 57), Color = new Color(148, 30, 34),
Archetypes = Archetypes.Comparisons.Nodes Archetypes = Archetypes.Comparisons.Nodes
}, },
// GroupID = 13 -> Custom Nodes provided externally // GroupID = 13 -> Custom Nodes provided externally
@@ -145,7 +145,7 @@ namespace FlaxEditor.Surface
{ {
GroupID = 14, GroupID = 14,
Name = "Particles", Name = "Particles",
Color = new Color(72, 125, 107), Color = new Color(121, 210, 176),
Archetypes = Archetypes.Particles.Nodes Archetypes = Archetypes.Particles.Nodes
}, },
new GroupArchetype new GroupArchetype
@@ -166,7 +166,7 @@ namespace FlaxEditor.Surface
{ {
GroupID = 17, GroupID = 17,
Name = "Flow", Name = "Flow",
Color = new Color(181, 91, 33), Color = new Color(237, 136, 64),
Archetypes = Archetypes.Flow.Nodes Archetypes = Archetypes.Flow.Nodes
}, },
new GroupArchetype new GroupArchetype

View File

@@ -78,11 +78,6 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
VariableValuesSize = 2048, VariableValuesSize = 2048,
/// <summary>
/// Node has fixed size defined and should not use automatic layout.
/// </summary>
FixedSize = 4096,
/// <summary> /// <summary>
/// Node can be used in the all visual graphs. /// Node can be used in the all visual graphs.
/// </summary> /// </summary>

View File

@@ -59,7 +59,7 @@ namespace FlaxEditor.Surface
var width = _rootNode.Width; var width = _rootNode.Width;
var rootPos = _rootNode.Location; var rootPos = _rootNode.Location;
var pos = rootPos; var pos = rootPos;
pos.Y += Constants.NodeHeaderHeight + 1.0f + 7 * Constants.LayoutOffsetY + 6.0f + 4.0f; pos.Y += Constants.NodeHeaderSize + 1.0f + 7 * Constants.LayoutOffsetY + 6.0f + 4.0f;
for (int i = 0; i < _rootNode.Headers.Length; i++) for (int i = 0; i < _rootNode.Headers.Length; i++)
{ {
@@ -67,7 +67,7 @@ namespace FlaxEditor.Surface
var modulesStart = pos - rootPos; var modulesStart = pos - rootPos;
var modules = modulesGroups.FirstOrDefault(x => x.Key == header.ModuleType); var modules = modulesGroups.FirstOrDefault(x => x.Key == header.ModuleType);
pos.Y += Constants.NodeHeaderHeight + 2.0f; pos.Y += Constants.NodeHeaderSize + 2.0f;
if (modules != null) if (modules != null)
{ {
foreach (var module in modules) foreach (var module in modules)

View File

@@ -74,12 +74,6 @@ namespace FlaxEditor.Surface
Resize(size.X, size.Y); Resize(size.X, size.Y);
} }
/// <inheritdoc />
public override void ResizeAuto()
{
// Do nothing, we want to put full control of node size into the users hands
}
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {

View File

@@ -56,10 +56,10 @@ namespace FlaxEditor.Surface
: base(id, context, nodeArch, groupArch) : base(id, context, nodeArch, groupArch)
{ {
_sizeValueIndex = 2; // Index of the Size stored in Values array _sizeValueIndex = 2; // Index of the Size stored in Values array
_sizeMin = new Float2(140.0f, Constants.NodeHeaderHeight); _sizeMin = new Float2(140.0f, Constants.NodeHeaderSize);
_renameTextBox = new TextBox(false, 0, 0, Width) _renameTextBox = new TextBox(false, 0, 0, Width)
{ {
Height = Constants.NodeHeaderHeight, Height = Constants.NodeHeaderSize,
Visible = false, Visible = false,
Parent = this, Parent = this,
EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header
@@ -124,11 +124,11 @@ namespace FlaxEditor.Surface
{ {
base.UpdateRectangles(); base.UpdateRectangles();
const float headerSize = Constants.NodeHeaderHeight; const float headerSize = Constants.NodeHeaderSize;
const float buttonMargin = Constants.NodeCloseButtonMargin; const float buttonMargin = Constants.NodeCloseButtonMargin;
const float buttonSize = Constants.NodeCloseButtonSize; const float buttonSize = Constants.NodeCloseButtonSize;
_headerRect = new Rectangle(0, 0, Width, headerSize); _headerRect = new Rectangle(0, 0, Width, headerSize);
_closeButtonRect = new Rectangle(Width - buttonSize * 0.75f - buttonMargin, buttonMargin, buttonSize * 0.75f, buttonSize * 0.75f); _closeButtonRect = new Rectangle(Width - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize);
_colorButtonRect = new Rectangle(_closeButtonRect.Left - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize); _colorButtonRect = new Rectangle(_closeButtonRect.Left - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize);
_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize); _resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize);
_renameTextBox.Width = Width; _renameTextBox.Width = Width;
@@ -183,7 +183,7 @@ namespace FlaxEditor.Surface
if (Surface.CanEdit) if (Surface.CanEdit)
{ {
// Close button // Close button
DrawCloseButton(_closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
// Color button // Color button
Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);

View File

@@ -40,13 +40,6 @@ namespace FlaxEditor.Surface
[HideInEditor] [HideInEditor]
public class SurfaceNode : SurfaceControl public class SurfaceNode : SurfaceControl
{ {
internal const float ShadowOffset = 2.25f;
/// <summary>
/// If true, draws a basic rectangle shadow behind the node. Disable to hide shadow or if the node is drawing a custom shadow.
/// </summary>
internal virtual bool DrawBasicShadow => true;
/// <summary> /// <summary>
/// The box to draw a highlight around. Drawing will be skipped if null. /// The box to draw a highlight around. Drawing will be skipped if null.
/// </summary> /// </summary>
@@ -62,11 +55,6 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
protected Rectangle _headerRect; protected Rectangle _headerRect;
/// <summary>
/// The header text rectangle (local space).
/// </summary>
protected Rectangle _headerTextRect;
/// <summary> /// <summary>
/// The close button rectangle (local space). /// The close button rectangle (local space).
/// </summary> /// </summary>
@@ -135,7 +123,7 @@ namespace FlaxEditor.Surface
/// <param name="nodeArch">The node archetype.</param> /// <param name="nodeArch">The node archetype.</param>
/// <param name="groupArch">The group archetype.</param> /// <param name="groupArch">The group archetype.</param>
public SurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) public SurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(context, nodeArch.Size.X + Constants.NodeMarginX * 2, nodeArch.Size.Y + Constants.NodeMarginY * 2 + Constants.NodeHeaderHeight + Constants.NodeFooterSize) : base(context, nodeArch.Size.X + Constants.NodeMarginX * 2, nodeArch.Size.Y + Constants.NodeMarginY * 2 + Constants.NodeHeaderSize + Constants.NodeFooterSize)
{ {
Title = nodeArch.Title; Title = nodeArch.Title;
ID = id; ID = id;
@@ -144,7 +132,7 @@ namespace FlaxEditor.Surface
AutoFocus = false; AutoFocus = false;
TooltipText = GetTooltip(); TooltipText = GetTooltip();
CullChildren = false; CullChildren = false;
BackgroundColor = Color.Lerp(Style.Current.Background, Style.Current.BackgroundHighlighted, 0.55f); BackgroundColor = Style.Current.BackgroundNormal;
if (Archetype.DefaultValues != null) if (Archetype.DefaultValues != null)
{ {
@@ -159,9 +147,9 @@ namespace FlaxEditor.Surface
public virtual string ContentSearchText => null; public virtual string ContentSearchText => null;
/// <summary> /// <summary>
/// Gets the color of the header of the node. /// Gets the color of the footer of the node.
/// </summary> /// </summary>
protected virtual Color ArchetypeColor => GroupArchetype.Color; protected virtual Color FooterColor => GroupArchetype.Color;
private Float2 mouseDownMousePosition; private Float2 mouseDownMousePosition;
@@ -173,7 +161,7 @@ namespace FlaxEditor.Surface
/// <returns>The node control total size.</returns> /// <returns>The node control total size.</returns>
protected virtual Float2 CalculateNodeSize(float width, float height) protected virtual Float2 CalculateNodeSize(float width, float height)
{ {
return new Float2(width + Constants.NodeMarginX * 2, height + Constants.NodeMarginY * 2 + Constants.NodeHeaderHeight + Constants.NodeFooterSize); return new Float2(width + Constants.NodeMarginX * 2, height + Constants.NodeMarginY * 2 + Constants.NodeHeaderSize + Constants.NodeFooterSize);
} }
/// <summary> /// <summary>
@@ -181,7 +169,7 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
public virtual void Resize(float width, float height) public void Resize(float width, float height)
{ {
if (Surface == null) if (Surface == null)
return; return;
@@ -199,7 +187,7 @@ namespace FlaxEditor.Surface
{ {
if (Elements[i] is OutputBox box) if (Elements[i] is OutputBox box)
{ {
box.Location = box.Archetype.Position + new Float2(width - Constants.NodeMarginX, 0); box.Location = box.Archetype.Position + new Float2(width, 0);
} }
} }
@@ -227,41 +215,30 @@ namespace FlaxEditor.Surface
var child = Children[i]; var child = Children[i];
if (!child.Visible) if (!child.Visible)
continue; continue;
// Input boxes
if (child is InputBox inputBox) if (child is InputBox inputBox)
{ {
var boxWidth = boxLabelFont.MeasureText(inputBox.Text).X + 25; var boxWidth = boxLabelFont.MeasureText(inputBox.Text).X + 20;
if (inputBox.DefaultValueEditor != null && inputBox.DefaultValueEditor.Visible) if (inputBox.DefaultValueEditor != null)
boxWidth += inputBox.DefaultValueEditor.Width + 4; boxWidth += inputBox.DefaultValueEditor.Width + 4;
leftWidth = Mathf.Max(leftWidth, boxWidth); leftWidth = Mathf.Max(leftWidth, boxWidth);
leftHeight = Mathf.Max(leftHeight, inputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderHeight + Constants.BoxRowHeight); leftHeight = Mathf.Max(leftHeight, inputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
} }
// Output boxes
else if (child is OutputBox outputBox) else if (child is OutputBox outputBox)
{ {
rightWidth = Mathf.Max(rightWidth, boxLabelFont.MeasureText(outputBox.Text).X + 25); rightWidth = Mathf.Max(rightWidth, boxLabelFont.MeasureText(outputBox.Text).X + 20);
rightHeight = Mathf.Max(rightHeight, outputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderHeight + Constants.BoxRowHeight); rightHeight = Mathf.Max(rightHeight, outputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
} }
// Elements (Float-, int-, uint- value boxes, asset pickers, etc.)
// These will only ever be on the left side of the node, so we only adjust left width and height
else if (child is SurfaceNodeElementControl elementControl)
{
leftWidth = Mathf.Max(leftWidth, elementControl.Width + 8f);
leftHeight = Mathf.Max(leftHeight, elementControl.Height);
}
// Other controls in the node
else if (child is Control control) else if (child is Control control)
{ {
if (control.AnchorPreset == AnchorPresets.TopLeft) if (control.AnchorPreset == AnchorPresets.TopLeft)
{ {
width = Mathf.Max(width, control.Right + 15 + Constants.NodeMarginX); width = Mathf.Max(width, control.Right + 4 - Constants.NodeMarginX);
height = Mathf.Max(height, control.Bottom - Constants.NodeMarginY - Constants.NodeHeaderHeight); height = Mathf.Max(height, control.Bottom + 4 - Constants.NodeMarginY - Constants.NodeHeaderSize);
} }
else if (!_headerRect.Intersects(control.Bounds)) else if (!_headerRect.Intersects(control.Bounds))
{ {
width = Mathf.Max(width, control.Width + 15 + Constants.NodeMarginX); width = Mathf.Max(width, control.Width + 4);
height = Mathf.Max(height, control.Height); height = Mathf.Max(height, control.Height + 4);
} }
} }
} }
@@ -348,9 +325,6 @@ namespace FlaxEditor.Surface
Elements.Add(element); Elements.Add(element);
if (element is Control control) if (element is Control control)
AddChild(control); AddChild(control);
if (!IsLayoutLocked)
UpdateSize();
} }
/// <summary> /// <summary>
@@ -391,7 +365,7 @@ namespace FlaxEditor.Surface
// Sync properties for exiting box // Sync properties for exiting box
box.Text = text; box.Text = text;
box.CurrentType = type; box.CurrentType = type;
box.Y = Constants.NodeMarginY + Constants.NodeHeaderHeight + yLevel * Constants.LayoutOffsetY; box.Y = Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY;
} }
// Update box // Update box
@@ -460,7 +434,7 @@ namespace FlaxEditor.Surface
private static readonly List<SurfaceNode> UpdateStack = new List<SurfaceNode>(); private static readonly List<SurfaceNode> UpdateStack = new List<SurfaceNode>();
/// <summary> /// <summary>
/// Updates dependent/independent boxes types. /// Updates dependant/independent boxes types.
/// </summary> /// </summary>
public void UpdateBoxesTypes() public void UpdateBoxesTypes()
{ {
@@ -802,24 +776,6 @@ namespace FlaxEditor.Surface
return output; return output;
} }
/// <summary>
/// Draws the close button inside of the <paramref name="rect"/>.
/// </summary>
/// <param name="rect">The rectangle to draw the close button in.</param>
/// <param name="color">The color of the close button.</param>
public void DrawCloseButton(Rectangle rect, Color color)
{
// Disable vertex snapping to reduce artefacts at the line ends
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
rect.Expand(-2f); // Don't overshoot the rectangle because of the thickness
Render2D.DrawLine(rect.TopLeft, rect.BottomRight, color, 2f);
Render2D.DrawLine(rect.BottomLeft, rect.TopRight, color, 2f);
Render2D.Features = features;
}
/// <summary> /// <summary>
/// Draws all the connections between surface objects related to this node. /// Draws all the connections between surface objects related to this node.
/// </summary> /// </summary>
@@ -911,14 +867,6 @@ namespace FlaxEditor.Surface
return sb.ToString(); return sb.ToString();
} }
private void UpdateSize()
{
if (Archetype.Flags.HasFlag(NodeFlags.FixedSize))
Resize(Archetype.Size.X, Archetype.Size.Y);
else
ResizeAuto();
}
/// <inheritdoc /> /// <inheritdoc />
protected override bool ShowTooltip => base.ShowTooltip && _headerRect.Contains(ref _mousePosition) && !Surface.IsLeftMouseButtonDown && !Surface.IsRightMouseButtonDown && !Surface.IsPrimaryMenuOpened; protected override bool ShowTooltip => base.ShowTooltip && _headerRect.Contains(ref _mousePosition) && !Surface.IsLeftMouseButtonDown && !Surface.IsRightMouseButtonDown && !Surface.IsPrimaryMenuOpened;
@@ -971,8 +919,6 @@ namespace FlaxEditor.Surface
if (Elements[i] is Box box) if (Elements[i] is Box box)
box.OnConnectionsChanged(); box.OnConnectionsChanged();
} }
UpdateSize();
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -1010,8 +956,6 @@ namespace FlaxEditor.Surface
Surface.AddBatchedUndoAction(new EditNodeValuesAction(this, before, graphEdited)); Surface.AddBatchedUndoAction(new EditNodeValuesAction(this, before, graphEdited));
_isDuringValuesEditing = false; _isDuringValuesEditing = false;
UpdateSize();
} }
/// <summary> /// <summary>
@@ -1046,8 +990,6 @@ namespace FlaxEditor.Surface
} }
_isDuringValuesEditing = false; _isDuringValuesEditing = false;
UpdateSize();
} }
internal void SetIsDuringValuesEditing(bool value) internal void SetIsDuringValuesEditing(bool value)
@@ -1056,7 +998,7 @@ namespace FlaxEditor.Surface
} }
/// <summary> /// <summary>
/// Sets teh node values from the given pasted source. Can be overridden to perform validation or custom values processing. /// Sets teh node values from the given pasted source. Can be overriden to perform validation or custom values processing.
/// </summary> /// </summary>
/// <param name="values">The input values array.</param> /// <param name="values">The input values array.</param>
public virtual void SetValuesPaste(object[] values) public virtual void SetValuesPaste(object[] values)
@@ -1080,18 +1022,16 @@ namespace FlaxEditor.Surface
public virtual void ConnectionTick(Box box) public virtual void ConnectionTick(Box box)
{ {
UpdateBoxesTypes(); UpdateBoxesTypes();
UpdateSize();
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void UpdateRectangles() protected override void UpdateRectangles()
{ {
const float footerSize = Constants.NodeFooterSize; const float footerSize = Constants.NodeFooterSize;
const float headerSize = Constants.NodeHeaderHeight; const float headerSize = Constants.NodeHeaderSize;
const float closeButtonMargin = Constants.NodeCloseButtonMargin; const float closeButtonMargin = Constants.NodeCloseButtonMargin;
const float closeButtonSize = Constants.NodeCloseButtonSize; const float closeButtonSize = Constants.NodeCloseButtonSize;
_headerRect = new Rectangle(0, 0, Width, headerSize); _headerRect = new Rectangle(0, 0, Width, headerSize);
_headerTextRect = _headerRect with { X = 5f, Width = Width - closeButtonSize - closeButtonMargin * 4f };
_closeButtonRect = new Rectangle(Width - closeButtonSize - closeButtonMargin, closeButtonMargin, closeButtonSize, closeButtonSize); _closeButtonRect = new Rectangle(Width - closeButtonSize - closeButtonMargin, closeButtonMargin, closeButtonSize, closeButtonSize);
_footerRect = new Rectangle(0, Height - footerSize, Width, footerSize); _footerRect = new Rectangle(0, Height - footerSize, Width, footerSize);
} }
@@ -1100,16 +1040,9 @@ namespace FlaxEditor.Surface
public override void Draw() public override void Draw()
{ {
var style = Style.Current; var style = Style.Current;
var backgroundRect = new Rectangle(Float2.Zero, Size);
// Shadow
if (DrawBasicShadow)
{
var shadowRect = backgroundRect.MakeOffsetted(ShadowOffset);
Render2D.FillRectangle(shadowRect, Color.Black.AlphaMultiplied(0.125f));
}
// Background // Background
var backgroundRect = new Rectangle(Float2.Zero, Size);
Render2D.FillRectangle(backgroundRect, BackgroundColor); Render2D.FillRectangle(backgroundRect, BackgroundColor);
// Breakpoint hit // Breakpoint hit
@@ -1125,18 +1058,18 @@ namespace FlaxEditor.Surface
var headerColor = style.BackgroundHighlighted; var headerColor = style.BackgroundHighlighted;
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting) if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting)
headerColor *= 1.07f; headerColor *= 1.07f;
Render2D.FillRectangle(_headerRect, ArchetypeColor); Render2D.FillRectangle(_headerRect, headerColor);
Render2D.DrawText(style.FontLarge, Title, _headerTextRect, style.Foreground, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1f, Constants.NodeHeaderTextScale); Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
// Close button // Close button
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit) if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
{ {
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting; bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting;
DrawCloseButton(_closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
} }
// Footer // Footer
Render2D.FillRectangle(_footerRect, ArchetypeColor); Render2D.FillRectangle(_footerRect, FooterColor);
DrawChildren(); DrawChildren();
@@ -1145,7 +1078,7 @@ namespace FlaxEditor.Surface
{ {
var colorTop = Color.Orange; var colorTop = Color.Orange;
var colorBottom = Color.OrangeRed; var colorBottom = Color.OrangeRed;
Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom, 2.5f); Render2D.DrawRectangle(backgroundRect, colorTop, colorTop, colorBottom, colorBottom);
} }
// Breakpoint dot // Breakpoint dot

View File

@@ -2,7 +2,6 @@
using System; using System;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
@@ -141,11 +140,6 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
public Texture Background; public Texture Background;
/// <summary>
/// The color used as a surface background.
/// </summary>
public Color BackgroundColor;
/// <summary> /// <summary>
/// Boxes drawing callback. /// Boxes drawing callback.
/// </summary> /// </summary>
@@ -222,20 +216,19 @@ namespace FlaxEditor.Surface
private static void DefaultDrawBox(Elements.Box box) private static void DefaultDrawBox(Elements.Box box)
{ {
var rect = new Rectangle(box.Width * 0.5f - Constants.BoxSize * 0.5f, box.Height * 0.5f - Constants.BoxSize * 0.5f, new Float2(Constants.BoxSize)); var rect = new Rectangle(Float2.Zero, box.Size);
// Size culling // Size culling
const float minBoxSize = 5.0f; const float minBoxSize = 5.0f;
if (rect.Size.LengthSquared < minBoxSize * minBoxSize) if (rect.Size.LengthSquared < minBoxSize * minBoxSize)
return; return;
// Debugging boxes size and bounds // Debugging boxes size
//Render2D.DrawRectangle(rect, Color.Orange); return; //Render2D.DrawRectangle(rect, Color.Orange); return;
//Render2D.DrawRectangle(box.Bounds, Color.Green);
// Draw icon // Draw icon
bool hasConnections = box.HasAnyConnection; bool hasConnections = box.HasAnyConnection;
float alpha = box.IsDisabled ? 0.6f : 1.0f; float alpha = box.Enabled && box.IsActive ? 1.0f : 0.6f;
Color color = box.CurrentTypeColor * alpha; Color color = box.CurrentTypeColor * alpha;
var style = box.Surface.Style; var style = box.Surface.Style;
SpriteHandle icon; SpriteHandle icon;
@@ -244,42 +237,20 @@ namespace FlaxEditor.Surface
else else
icon = hasConnections ? style.Icons.BoxClose : style.Icons.BoxOpen; icon = hasConnections ? style.Icons.BoxClose : style.Icons.BoxOpen;
color *= box.ConnectionsHighlightIntensity + 1; color *= box.ConnectionsHighlightIntensity + 1;
if (box.IsMouseOver)
{
color *= 1.3f;
rect = rect.MakeExpanded(1.0f);
}
// Disable vertex snapping to prevent position jitter/snapping artefacts for the boxes when zooming the surface
var features = Render2D.Features;
Render2D.Features = features & ~Render2D.RenderingFeatures.VertexSnapping;
Render2D.DrawSprite(icon, rect, color); Render2D.DrawSprite(icon, rect, color);
// Draw connected hint with color from connected output box
if (hasConnections && box.Connections[0] is OutputBox connectedOutputBox)
{
bool connectedSameColor = connectedOutputBox.CurrentTypeColor == box.CurrentTypeColor;
Color innerColor = connectedSameColor ? color.RGBMultiplied(0.4f) : connectedOutputBox.CurrentTypeColor;
innerColor = innerColor * alpha;
Render2D.DrawSprite(icon, rect.MakeExpanded(-5.0f), innerColor);
}
// Draw selection hint // Draw selection hint
if (box.IsSelected) if (box.IsSelected)
{ {
float outlineAlpha = Mathf.Sin(Time.TimeSinceStartup * 4.0f) * 0.5f + 0.5f; float outlineAlpha = Mathf.Sin(Time.TimeSinceStartup * 4.0f) * 0.5f + 0.5f;
float outlineWidth = Mathf.Lerp(1.5f, 4.0f, outlineAlpha); float outlineWidth = Mathf.Lerp(1.5f, 4.0f, outlineAlpha);
var outlineRect = new Rectangle(rect.X - outlineWidth, rect.Y - outlineWidth, rect.Width + outlineWidth * 2, rect.Height + outlineWidth * 2); var outlineRect = new Rectangle(rect.X - outlineWidth, rect.Y - outlineWidth, rect.Width + outlineWidth * 2, rect.Height + outlineWidth * 2);
Color selectionColor = FlaxEngine.GUI.Style.Current.BorderSelected.RGBMultiplied(1.0f + outlineAlpha * 0.4f); Render2D.DrawSprite(icon, outlineRect, FlaxEngine.GUI.Style.Current.BorderSelected.RGBMultiplied(1.0f + outlineAlpha * 0.4f));
Render2D.DrawSprite(icon, outlineRect, selectionColor.AlphaMultiplied(0.4f));
} }
Render2D.Features = features;
} }
/// <summary> /// <summary>
/// Function used to create style for the given surface type. Can be overridden to provide some customization via user plugin. /// Function used to create style for the given surface type. Can be overriden to provide some customization via user plugin.
/// </summary> /// </summary>
public static Func<Editor, SurfaceStyle> CreateStyleHandler = CreateDefault; public static Func<Editor, SurfaceStyle> CreateStyleHandler = CreateDefault;
@@ -322,7 +293,6 @@ namespace FlaxEditor.Surface
ArrowClose = editor.Icons.VisjectArrowClosed32, ArrowClose = editor.Icons.VisjectArrowClosed32,
}, },
Background = editor.UI.VisjectSurfaceBackground, Background = editor.UI.VisjectSurfaceBackground,
BackgroundColor = new Color(31, 31, 31),
}; };
} }
@@ -341,11 +311,13 @@ namespace FlaxEditor.Surface
{ {
var dir = sub / length; var dir = sub / length;
var arrowRect = new Rectangle(0, 0, 16.0f, 16.0f); var arrowRect = new Rectangle(0, 0, 16.0f, 16.0f);
float rotation = Mathf.Atan2(dir.Y, dir.X); float rotation = Float2.Dot(dir, Float2.UnitY);
if (endPos.X < startPos.X)
rotation = 2 - rotation;
var sprite = Editor.Instance.Icons.VisjectArrowClosed32; var sprite = Editor.Instance.Icons.VisjectArrowClosed32;
var arrowTransform = var arrowTransform =
Matrix3x3.Translation2D(-6.5f, -8) * Matrix3x3.Translation2D(-6.5f, -8) *
Matrix3x3.RotationZ(rotation) * Matrix3x3.RotationZ(rotation * Mathf.PiOverTwo) *
Matrix3x3.Translation2D(endPos - dir * 8); Matrix3x3.Translation2D(endPos - dir * 8);
Render2D.PushTransform(ref arrowTransform); Render2D.PushTransform(ref arrowTransform);

View File

@@ -574,13 +574,13 @@ namespace FlaxEditor.Surface
var showSearch = () => editor.ContentFinding.ShowSearch(window); var showSearch = () => editor.ContentFinding.ShowSearch(window);
// Toolstrip // Toolstrip
saveButton = toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save.", ref inputOptions.Save); saveButton = toolStrip.AddButton(editor.Icons.Save64, window.Save).LinkTooltip("Save", ref inputOptions.Save);
toolStrip.AddSeparator(); toolStrip.AddSeparator();
undoButton = toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip("Undo.", ref inputOptions.Undo); undoButton = toolStrip.AddButton(editor.Icons.Undo64, undo.PerformUndo).LinkTooltip("Undo", ref inputOptions.Undo);
redoButton = toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip("Redo.", ref inputOptions.Redo); redoButton = toolStrip.AddButton(editor.Icons.Redo64, undo.PerformRedo).LinkTooltip("Redo", ref inputOptions.Redo);
toolStrip.AddSeparator(); toolStrip.AddSeparator();
toolStrip.AddButton(editor.Icons.Search64, showSearch).LinkTooltip("Open content search tool.", ref inputOptions.Search); toolStrip.AddButton(editor.Icons.Search64, showSearch).LinkTooltip("Open content search tool", ref inputOptions.Search);
toolStrip.AddButton(editor.Icons.CenterView64, surface.ShowWholeGraph).LinkTooltip("Show whole graph."); toolStrip.AddButton(editor.Icons.CenterView64, surface.ShowWholeGraph).LinkTooltip("Show whole graph");
var gridSnapButton = toolStrip.AddButton(editor.Icons.Grid32, surface.ToggleGridSnapping); var gridSnapButton = toolStrip.AddButton(editor.Icons.Grid32, surface.ToggleGridSnapping);
gridSnapButton.LinkTooltip("Toggle grid snapping for nodes."); gridSnapButton.LinkTooltip("Toggle grid snapping for nodes.");
gridSnapButton.AutoCheck = true; gridSnapButton.AutoCheck = true;

View File

@@ -410,11 +410,8 @@ namespace FlaxEditor.Surface
} }
menu.AddSeparator(); menu.AddSeparator();
bool allNodesNoMove = SelectedNodes.All(n => n.Archetype.Flags.HasFlag(NodeFlags.NoMove)); _cmFormatNodesMenu = menu.AddChildMenu("Format node(s)");
bool clickedNodeNoMove = ((SelectedNodes.Count == 1 && controlUnderMouse is SurfaceNode n && n.Archetype.Flags.HasFlag(NodeFlags.NoMove))); _cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection;
_cmFormatNodesMenu = menu.AddChildMenu("Format nodes");
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection && !(allNodesNoMove || clickedNodeNoMove);
_cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }); _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); });
_cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Straighten connections", Editor.Instance.Options.Options.Input.NodesStraightenConnections, () => { StraightenGraphConnections(SelectedNodes); }); _cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Straighten connections", Editor.Instance.Options.Options.Input.NodesStraightenConnections, () => { StraightenGraphConnections(SelectedNodes); });

View File

@@ -65,68 +65,31 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
protected virtual void DrawBackground() protected virtual void DrawBackground()
{ {
DrawBackgroundDefault(Style.Background, Size, _rootControl.Location); DrawBackgroundDefault(Style.Background, Width, Height);
//DrawBackgroundSolidColor(Style.BackgroundColor, Width, Height);
DrawGridBackground();
} }
internal static void DrawBackgroundSolidColor(Color color, float width, float height) internal static void DrawBackgroundDefault(Texture background, float width, float height)
{
Rectangle backgroundRect = new Rectangle(0f, 0f, width, height);
Render2D.FillRectangle(backgroundRect, color);
}
internal void DrawGridBackground()
{
var viewRect = GetClientArea();
var upperLeft = _rootControl.PointFromParent(viewRect.Location);
var bottomRight = _rootControl.PointFromParent(viewRect.Size);
var min = Float2.Min(upperLeft, bottomRight);
var max = Float2.Max(upperLeft, bottomRight);
var pixelRange = (max - min) * ViewScale * 2.75f;
Render2D.PushClip(ref viewRect);
DrawAxis(Float2.UnitX, viewRect, min.X, max.X, pixelRange.X);
DrawAxis(Float2.UnitY, viewRect, min.Y, max.Y, pixelRange.Y);
Render2D.PopClip();
}
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
{
var linesColor = Style.BackgroundColor.RGBMultiplied(1.2f);
float[] gridTickStrengths = null;
Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
{
var p = _rootControl.PointToParent(axis * (float)tick); ;
// Draw line
var lineRect = new Rectangle
(
viewRect.Location + (p - 0.5f) * axis,
Float2.Lerp(viewRect.Size, Float2.One, axis)
);
Render2D.FillRectangle(lineRect, linesColor.AlphaMultiplied(strength));
}, Utilities.Utils.CurveTickSteps, ref gridTickStrengths, min, max, pixelRange);
}
internal static void DrawBackgroundDefault(Texture background, Float2 size, Float2 offset)
{ {
if (background && background.ResidentMipLevels > 0) if (background && background.ResidentMipLevels > 0)
{ {
var bSize = background.Size; var bSize = background.Size;
var pos = Float2.Mod(offset / bSize) * bSize; float bw = bSize.X;
var max = Float2.Ceil(size / bSize + 1.0f); float bh = bSize.Y;
var pos = Float2.Mod(bSize);
if (pos.X > 0) if (pos.X > 0)
pos.X -= bSize.X; pos.X -= bw;
if (pos.Y > 0) if (pos.Y > 0)
pos.Y -= bSize.Y; pos.Y -= bh;
for (int i = 0; i < max.X; i++) int maxI = Mathf.CeilToInt(width / bw + 1.0f);
int maxJ = Mathf.CeilToInt(height / bh + 1.0f);
for (int i = 0; i < maxI; i++)
{ {
for (int j = 0; j < max.Y; j++) for (int j = 0; j < maxJ; j++)
{ {
Render2D.DrawTexture(background, new Rectangle(pos.X + i * bSize.X, pos.Y + j * bSize.Y, bSize), Color.White); Render2D.DrawTexture(background, new Rectangle(pos.X + i * bw, pos.Y + j * bh, bw, bh), Color.White);
} }
} }
} }
@@ -250,44 +213,6 @@ namespace FlaxEditor.Surface
} }
} }
/// <summary>
/// Draw connection hints for lazy connect feature.
/// </summary>
protected virtual void DrawLazyConnect()
{
var style = FlaxEngine.GUI.Style.Current;
if (_lazyConnectStartNode != null)
{
Float2 upperLeft = _rootControl.PointToParent(_lazyConnectStartNode.UpperLeft);
Rectangle startNodeOutline = new Rectangle(upperLeft + 1f, _lazyConnectStartNode.Size - 1f);
startNodeOutline.Size *= ViewScale;
Render2D.DrawRectangle(startNodeOutline.MakeExpanded(4f), style.BackgroundSelected, 4f);
}
if (_lazyConnectEndNode != null)
{
Float2 upperLeft = _rootControl.PointToParent(_lazyConnectEndNode.UpperLeft);
Rectangle startNodeOutline = new Rectangle(upperLeft + 1f, _lazyConnectEndNode.Size - 1f);
startNodeOutline.Size *= ViewScale;
Render2D.DrawRectangle(startNodeOutline.MakeExpanded(4f), style.BackgroundSelected, 4f);
}
Rectangle startRect = new Rectangle(_rightMouseDownPos - 6f, new Float2(12f));
Rectangle endRect = new Rectangle(_mousePos - 6f, new Float2(12f));
// Start and end shadows/ outlines
Render2D.FillRectangle(startRect.MakeExpanded(2.5f), Color.Black);
Render2D.FillRectangle(endRect.MakeExpanded(2.5f), Color.Black);
Render2D.DrawLine(_rightMouseDownPos, _mousePos, Color.Black, 7.5f);
Render2D.DrawLine(_rightMouseDownPos, _mousePos, style.ForegroundGrey, 5f);
// Draw start and end boxes over the lines to hide ugly artifacts at the ends
Render2D.FillRectangle(startRect, style.ForegroundGrey);
Render2D.FillRectangle(endRect, style.ForegroundGrey);
}
/// <summary> /// <summary>
/// Draws the contents of the surface (nodes, connections, comments, etc.). /// Draws the contents of the surface (nodes, connections, comments, etc.).
/// </summary> /// </summary>
@@ -335,9 +260,6 @@ namespace FlaxEditor.Surface
DrawContents(); DrawContents();
if (_isLazyConnecting)
DrawLazyConnect();
//Render2D.DrawText(style.FontTitle, string.Format("Scale: {0}", _rootControl.Scale), rect, Enabled ? Color.Red : Color.Black); //Render2D.DrawText(style.FontTitle, string.Format("Scale: {0}", _rootControl.Scale), rect, Enabled ? Color.Red : Color.Black);
// Draw border // Draw border

View File

@@ -39,8 +39,6 @@ namespace FlaxEditor.Surface
if (nodes.Count <= 1) if (nodes.Count <= 1)
return; return;
List<MoveNodesAction> undoActions = new List<MoveNodesAction>();
var nodesToVisit = new HashSet<SurfaceNode>(nodes); var nodesToVisit = new HashSet<SurfaceNode>(nodes);
// While we haven't formatted every node // While we haven't formatted every node
@@ -75,23 +73,18 @@ namespace FlaxEditor.Surface
} }
} }
undoActions.AddRange(FormatConnectedGraph(connectedNodes)); FormatConnectedGraph(connectedNodes);
} }
Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
MarkAsEdited(false);
} }
/// <summary> /// <summary>
/// Formats a graph where all nodes are connected. /// Formats a graph where all nodes are connected.
/// </summary> /// </summary>
/// <param name="nodes">List of connected nodes.</param> /// <param name="nodes">List of connected nodes.</param>
private List<MoveNodesAction> FormatConnectedGraph(List<SurfaceNode> nodes) protected void FormatConnectedGraph(List<SurfaceNode> nodes)
{ {
List<MoveNodesAction> undoActions = new List<MoveNodesAction>();
if (nodes.Count <= 1) if (nodes.Count <= 1)
return undoActions; return;
var boundingBox = GetNodesBounds(nodes); var boundingBox = GetNodesBounds(nodes);
@@ -147,6 +140,7 @@ namespace FlaxEditor.Surface
} }
// Set the node positions // Set the node positions
var undoActions = new List<MoveNodesAction>();
var topRightPosition = endNodes[0].Location; var topRightPosition = endNodes[0].Location;
for (int i = 0; i < nodes.Count; i++) for (int i = 0; i < nodes.Count; i++)
{ {
@@ -161,18 +155,16 @@ namespace FlaxEditor.Surface
} }
} }
return undoActions; MarkAsEdited(false);
Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
} }
/// <summary> /// <summary>
/// Straightens every connection between nodes in <paramref name="nodes"/>. /// Straightens every connection between nodes in <paramref name="nodes"/>.
/// </summary> /// </summary>
/// <param name="nodes">List of nodes.</param> /// <param name="nodes">List of nodes.</param>
/// <returns>List of undo actions.</returns>
public void StraightenGraphConnections(List<SurfaceNode> nodes) public void StraightenGraphConnections(List<SurfaceNode> nodes)
{ {
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList();
if (nodes.Count <= 1) if (nodes.Count <= 1)
return; return;
@@ -358,10 +350,8 @@ namespace FlaxEditor.Surface
/// <param name="nodes">List of nodes.</param> /// <param name="nodes">List of nodes.</param>
/// <param name="alignmentType">Alignemnt type.</param> /// <param name="alignmentType">Alignemnt type.</param>
public void AlignNodes(List<SurfaceNode> nodes, NodeAlignmentType alignmentType) public void AlignNodes(List<SurfaceNode> nodes, NodeAlignmentType alignmentType)
{ {
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList(); if(nodes.Count <= 1)
if (nodes.Count <= 1)
return; return;
var undoActions = new List<MoveNodesAction>(); var undoActions = new List<MoveNodesAction>();
@@ -402,8 +392,6 @@ namespace FlaxEditor.Surface
/// <param name="vertically">If false will be done horizontally, if true will be done vertically.</param> /// <param name="vertically">If false will be done horizontally, if true will be done vertically.</param>
public void DistributeNodes(List<SurfaceNode> nodes, bool vertically) public void DistributeNodes(List<SurfaceNode> nodes, bool vertically)
{ {
nodes = nodes.Where(n => !n.Archetype.Flags.HasFlag(NodeFlags.NoMove)).ToList();
if(nodes.Count <= 1) if(nodes.Count <= 1)
return; return;

View File

@@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using static FlaxEditor.Surface.Archetypes.Particles;
using FlaxEditor.Options; using FlaxEditor.Options;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEditor.Surface.Undo; using FlaxEditor.Surface.Undo;
@@ -24,26 +23,12 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
public bool PanWithMiddleMouse = false; public bool PanWithMiddleMouse = false;
/// <summary>
/// Distance for the mouse to be considered above the connection.
/// </summary>
public float MouseOverConnectionDistance => 100f / ViewScale;
/// <summary>
/// Distance of a node from which it is able to be slotted into an existing connection.
/// </summary>
public float SlotNodeIntoConnectionDistance => 250f / ViewScale;
private string _currentInputText = string.Empty; private string _currentInputText = string.Empty;
private Float2 _movingNodesDelta; private Float2 _movingNodesDelta;
private Float2 _gridRoundingDelta; private Float2 _gridRoundingDelta;
private HashSet<SurfaceNode> _movingNodes; private HashSet<SurfaceNode> _movingNodes;
private HashSet<SurfaceNode> _temporarySelectedNodes; private HashSet<SurfaceNode> _temporarySelectedNodes;
private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>(); private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>();
private bool _isLazyConnecting;
private SurfaceNode _lazyConnectStartNode;
private SurfaceNode _lazyConnectEndNode;
private InputBinding _focusSelectedNodeBinding;
private class InputBracket private class InputBracket
{ {
@@ -265,13 +250,8 @@ namespace FlaxEditor.Surface
// Cache mouse location // Cache mouse location
_mousePos = location; _mousePos = location;
if (_isLazyConnecting && GetControlUnderMouse() is SurfaceNode nodeUnderMouse && !(nodeUnderMouse is SurfaceComment || nodeUnderMouse is ParticleEmitterNode))
_lazyConnectEndNode = nodeUnderMouse;
else if (_isLazyConnecting && Nodes.Count > 0)
_lazyConnectEndNode = GetClosestNodeAtLocation(location);
// Moving around surface with mouse // Moving around surface with mouse
if (_rightMouseDown && !_isLazyConnecting) if (_rightMouseDown)
{ {
// Calculate delta // Calculate delta
var delta = location - _rightMouseDownPos; var delta = location - _rightMouseDownPos;
@@ -341,33 +321,6 @@ namespace FlaxEditor.Surface
foreach (var node in _movingNodes) foreach (var node in _movingNodes)
{ {
// Allow ripping the node from its current connection
if (RootWindow.GetKey(KeyboardKeys.Alt))
{
InputBox nodeConnectedInput = null;
OutputBox nodeConnectedOuput = null;
var boxes = node.GetBoxes();
foreach (var box in boxes)
{
if (!box.IsOutput && box.Connections.Count > 0)
{
nodeConnectedInput = (InputBox)box;
continue;
}
if (box.IsOutput && box.Connections.Count > 0)
{
nodeConnectedOuput = (OutputBox)box;
continue;
}
}
if (nodeConnectedInput != null && nodeConnectedOuput != null)
TryConnect(nodeConnectedOuput.Connections[0], nodeConnectedInput.Connections[0]);
node.RemoveConnections();
}
if (gridSnap) if (gridSnap)
{ {
Float2 unroundedLocation = node.Location; Float2 unroundedLocation = node.Location;
@@ -467,7 +420,7 @@ namespace FlaxEditor.Surface
if (!handled && CanEdit && CanUseNodeType(7, 29)) if (!handled && CanEdit && CanUseNodeType(7, 29))
{ {
var mousePos = _rootControl.PointFromParent(ref _mousePos); var mousePos = _rootControl.PointFromParent(ref _mousePos);
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox, MouseOverConnectionDistance) && GetControlUnderMouse() == null) if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox) && GetControlUnderMouse() == null)
{ {
if (Undo != null) if (Undo != null)
{ {
@@ -562,17 +515,11 @@ namespace FlaxEditor.Surface
_middleMouseDownPos = location; _middleMouseDownPos = location;
} }
if (root.GetKey(KeyboardKeys.Alt) && button == MouseButton.Right)
_isLazyConnecting = true;
// Check if any node is under the mouse // Check if any node is under the mouse
SurfaceControl controlUnderMouse = GetControlUnderMouse(); SurfaceControl controlUnderMouse = GetControlUnderMouse();
var cLocation = _rootControl.PointFromParent(ref location); var cLocation = _rootControl.PointFromParent(ref location);
if (controlUnderMouse != null) if (controlUnderMouse != null)
{ {
if (controlUnderMouse is SurfaceNode node && _isLazyConnecting && !(controlUnderMouse is SurfaceComment || controlUnderMouse is ParticleEmitterNode))
_lazyConnectStartNode = node;
// Check if mouse is over header and user is pressing mouse left button // Check if mouse is over header and user is pressing mouse left button
if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation)) if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation))
{ {
@@ -607,9 +554,6 @@ namespace FlaxEditor.Surface
} }
else else
{ {
if (_isLazyConnecting && Nodes.Count > 0)
_lazyConnectStartNode = GetClosestNodeAtLocation(location);
// Cache flags and state // Cache flags and state
if (_leftMouseDown) if (_leftMouseDown)
{ {
@@ -658,71 +602,8 @@ namespace FlaxEditor.Surface
{ {
if (_movingNodes != null && _movingNodes.Count > 0) if (_movingNodes != null && _movingNodes.Count > 0)
{ {
// Allow dropping a single node onto an existing connection and connect it
if (_movingNodes.Count == 1)
{
var mousePos = _rootControl.PointFromParent(ref _mousePos);
InputBox intersectedConnectionInputBox;
OutputBox intersectedConnectionOutputBox;
if (IntersectsConnection(mousePos, out intersectedConnectionInputBox, out intersectedConnectionOutputBox, SlotNodeIntoConnectionDistance))
{
SurfaceNode node = _movingNodes.First();
InputBox nodeInputBox = (InputBox)node.GetBoxes().First(b => !b.IsOutput);
OutputBox nodeOutputBox = (OutputBox)node.GetBoxes().First(b => b.IsOutput);
TryConnect(intersectedConnectionOutputBox, nodeInputBox);
TryConnect(nodeOutputBox, intersectedConnectionInputBox);
float intersectedConnectionNodesXDistance = intersectedConnectionInputBox.ParentNode.Left - intersectedConnectionOutputBox.ParentNode.Right;
float paddedNodeWidth = node.Width + 2f;
if (intersectedConnectionNodesXDistance < paddedNodeWidth)
{
List<SurfaceNode> visitedNodes = new List<SurfaceNode>{ node };
List<SurfaceNode> movedNodes = new List<SurfaceNode>();
Float2 locationDelta = new Float2(paddedNodeWidth, 0f);
MoveConnectedNodes(intersectedConnectionInputBox.ParentNode);
void MoveConnectedNodes(SurfaceNode node)
{
// Only move node if it is to the right of the node we have connected the moved node to
if (node.Right > intersectedConnectionInputBox.ParentNode.Left + 15f && !node.Archetype.Flags.HasFlag(NodeFlags.NoMove))
{
node.Location += locationDelta;
movedNodes.Add(node);
}
visitedNodes.Add(node);
foreach (var box in node.GetBoxes())
{
if (!box.HasAnyConnection || box == intersectedConnectionInputBox)
continue;
foreach (var connectedBox in box.Connections)
{
SurfaceNode nextNode = connectedBox.ParentNode;
if (visitedNodes.Contains(nextNode))
continue;
MoveConnectedNodes(nextNode);
}
}
}
Float2 nodeMoveOffset = new Float2(node.Width * 0.5f, 0f);
node.Location += nodeMoveOffset;
var moveNodesAction = new MoveNodesAction(Context, movedNodes.Select(n => n.ID).ToArray(), locationDelta);
var moveNodeAction = new MoveNodesAction(Context, [node.ID], nodeMoveOffset);
var multiAction = new MultiUndoAction(moveNodeAction, moveNodesAction);
AddBatchedUndoAction(multiAction);
}
}
}
if (Undo != null && !_movingNodesDelta.IsZero && CanEdit) if (Undo != null && !_movingNodesDelta.IsZero && CanEdit)
AddBatchedUndoAction(new MoveNodesAction(Context, _movingNodes.Select(x => x.ID).ToArray(), _movingNodesDelta)); Undo.AddAction(new MoveNodesAction(Context, _movingNodes.Select(x => x.ID).ToArray(), _movingNodesDelta));
_movingNodes.Clear(); _movingNodes.Clear();
} }
_movingNodesDelta = Float2.Zero; _movingNodesDelta = Float2.Zero;
@@ -749,36 +630,12 @@ namespace FlaxEditor.Surface
{ {
// Check if any control is under the mouse // Check if any control is under the mouse
_cmStartPos = location; _cmStartPos = location;
if (controlUnderMouse == null && !_isLazyConnecting) if (controlUnderMouse == null)
{ {
showPrimaryMenu = true; showPrimaryMenu = true;
} }
} }
_mouseMoveAmount = 0; _mouseMoveAmount = 0;
if (_isLazyConnecting)
{
if (_lazyConnectStartNode != null && _lazyConnectEndNode != null && _lazyConnectStartNode != _lazyConnectEndNode)
{
// First check if there is a type matching input and output where input
OutputBox startNodeOutput = (OutputBox)_lazyConnectStartNode.GetBoxes().FirstOrDefault(b => b.IsOutput, null);
InputBox endNodeInput = null;
if (startNodeOutput != null)
endNodeInput = (InputBox)_lazyConnectEndNode.GetBoxes().FirstOrDefault(b => !b.IsOutput && b.CurrentType == startNodeOutput.CurrentType && !b.HasAnyConnection && b.IsActive && b.CanConnectWith(startNodeOutput), null);
// Perform less strict checks (less ideal conditions for connection but still good) if the first checks failed
if (endNodeInput == null)
endNodeInput = (InputBox)_lazyConnectEndNode.GetBoxes().FirstOrDefault(b => !b.IsOutput && !b.HasAnyConnection && b.CanConnectWith(startNodeOutput), null);
if (startNodeOutput != null && endNodeInput != null)
TryConnect(startNodeOutput, endNodeInput);
}
_isLazyConnecting = false;
_lazyConnectStartNode = null;
_lazyConnectEndNode = null;
}
} }
if (_middleMouseDown && button == MouseButton.Middle) if (_middleMouseDown && button == MouseButton.Middle)
{ {
@@ -794,7 +651,7 @@ namespace FlaxEditor.Surface
{ {
// Surface was not moved with MMB so try to remove connection underneath // Surface was not moved with MMB so try to remove connection underneath
var mousePos = _rootControl.PointFromParent(ref location); var mousePos = _rootControl.PointFromParent(ref location);
if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox, MouseOverConnectionDistance)) if (IntersectsConnection(mousePos, out InputBox inputBox, out OutputBox outputBox))
{ {
var action = new EditNodeConnections(inputBox.ParentNode.Context, inputBox.ParentNode); var action = new EditNodeConnections(inputBox.ParentNode.Context, inputBox.ParentNode);
inputBox.BreakConnection(outputBox); inputBox.BreakConnection(outputBox);
@@ -847,21 +704,13 @@ namespace FlaxEditor.Surface
private void MoveSelectedNodes(Float2 delta) private void MoveSelectedNodes(Float2 delta)
{ {
List<MoveNodesAction> undoActions = new List<MoveNodesAction>(); // TODO: undo
delta /= _targetScale; delta /= _targetScale;
OnGetNodesToMove(); OnGetNodesToMove();
foreach (var node in _movingNodes) foreach (var node in _movingNodes)
{
node.Location += delta; node.Location += delta;
if (Undo != null)
undoActions.Add(new MoveNodesAction(Context, new[] { node.ID }, delta));
}
_isMovingSelection = false; _isMovingSelection = false;
MarkAsEdited(false); MarkAsEdited(false);
if (undoActions.Count > 0)
Undo?.AddAction(new MultiUndoAction(undoActions, "Moved "));
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -988,29 +837,6 @@ namespace FlaxEditor.Surface
return false; return false;
} }
private SurfaceNode GetClosestNodeAtLocation(Float2 location)
{
SurfaceNode currentClosestNode = null;
float currentClosestDistanceSquared = float.MaxValue;
foreach (var node in Nodes)
{
if (node is SurfaceComment || node is ParticleEmitterNode)
continue;
Float2 nodeSurfaceLocation = _rootControl.PointToParent(node.Center);
float distanceSquared = Float2.DistanceSquared(location, nodeSurfaceLocation);
if (distanceSquared < currentClosestDistanceSquared)
{
currentClosestNode = node;
currentClosestDistanceSquared = distanceSquared;
}
}
return currentClosestNode;
}
private void ResetInput() private void ResetInput()
{ {
InputText = ""; InputText = "";
@@ -1019,8 +845,7 @@ namespace FlaxEditor.Surface
private void CurrentInputTextChanged(string currentInputText) private void CurrentInputTextChanged(string currentInputText)
{ {
// Check if focus selected nodes binding is being pressed to prevent it triggering primary menu if (string.IsNullOrEmpty(currentInputText))
if (string.IsNullOrEmpty(currentInputText) || _focusSelectedNodeBinding.Process(RootWindow))
return; return;
if (IsPrimaryMenuOpened || !CanEdit) if (IsPrimaryMenuOpened || !CanEdit)
{ {
@@ -1200,7 +1025,7 @@ namespace FlaxEditor.Surface
return new Float2(xLocation, yLocation); return new Float2(xLocation, yLocation);
} }
private bool IntersectsConnection(Float2 mousePosition, out InputBox inputBox, out OutputBox outputBox, float distance) private bool IntersectsConnection(Float2 mousePosition, out InputBox inputBox, out OutputBox outputBox)
{ {
for (int i = 0; i < Nodes.Count; i++) for (int i = 0; i < Nodes.Count; i++)
{ {
@@ -1210,7 +1035,7 @@ namespace FlaxEditor.Surface
{ {
for (int k = 0; k < ob.Connections.Count; k++) for (int k = 0; k < ob.Connections.Count; k++)
{ {
if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition, distance)) if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition))
{ {
outputBox = ob; outputBox = ob;
inputBox = ob.Connections[k] as InputBox; inputBox = ob.Connections[k] as InputBox;

View File

@@ -217,7 +217,7 @@ namespace FlaxEditor.Surface
set set
{ {
// Clamp // Clamp
value = Mathf.Clamp(value, 0.05f, 1.85f); value = Mathf.Clamp(value, 0.05f, 1.6f);
// Check if value will change // Check if value will change
if (Mathf.Abs(value - _targetScale) > 0.0001f) if (Mathf.Abs(value - _targetScale) > 0.0001f)
@@ -423,9 +423,8 @@ namespace FlaxEditor.Surface
new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }), new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }),
new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }), new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }),
new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }), new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }),
new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }), new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }),
new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }), new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }),
new InputActionsContainer.Binding(options => options.FocusSelectedNodes, () => { FocusSelectionOrWholeGraph(); }),
}); });
Context.ControlSpawned += OnSurfaceControlSpawned; Context.ControlSpawned += OnSurfaceControlSpawned;
@@ -437,10 +436,7 @@ namespace FlaxEditor.Surface
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem)); DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter)); DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
OnEditorOptionsChanged(Editor.Instance.Options.Options);
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin; ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
} }
private void OnScriptsReloadBegin() private void OnScriptsReloadBegin()
@@ -450,11 +446,6 @@ namespace FlaxEditor.Surface
_cmPrimaryMenu = null; _cmPrimaryMenu = null;
} }
private void OnEditorOptionsChanged(EditorOptions options)
{
_focusSelectedNodeBinding = options.Input.FocusSelectedNodes;
}
/// <summary> /// <summary>
/// Gets the display name of the connection type used in the surface. /// Gets the display name of the connection type used in the surface.
/// </summary> /// </summary>
@@ -511,7 +502,7 @@ namespace FlaxEditor.Surface
{ {
GroupID = Custom.GroupID, GroupID = Custom.GroupID,
Name = "Custom", Name = "Custom",
Color = Color.Wheat.RGBMultiplied(0.4f), Color = Color.Wheat
}; };
} }
else else
@@ -592,11 +583,6 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
public virtual bool CanSetParameters => false; public virtual bool CanSetParameters => false;
/// <summary>
/// Gets a value indicating whether surface private parameters can be used, otherwise they will remain hidden.
/// </summary>
public virtual bool CanShowPrivateParameters => false;
/// <summary> /// <summary>
/// True of the context menu should make use of a description panel drawn at the bottom of the menu /// True of the context menu should make use of a description panel drawn at the bottom of the menu
/// </summary> /// </summary>
@@ -657,37 +643,6 @@ namespace FlaxEditor.Surface
ViewCenterPosition = areaRect.Center; ViewCenterPosition = areaRect.Center;
} }
/// <summary>
/// Adjusts the view to focus on the currently selected nodes, or the entire graph if no nodes are selected.
/// </summary>
public void FocusSelectionOrWholeGraph()
{
if (SelectedNodes.Count > 0)
ShowSelection();
else
ShowWholeGraph();
}
/// <summary>
/// Shows the selected controls by changing the view scale and the position.
/// </summary>
public void ShowSelection()
{
var selection = SelectedControls;
if (selection.Count == 0)
return;
// Calculate the bounds of all selected controls
Rectangle bounds = selection[0].Bounds;
for (int i = 1; i < selection.Count; i++)
bounds = Rectangle.Union(bounds, selection[i].Bounds);
// Add margin
bounds = bounds.MakeExpanded(250.0f);
ShowArea(bounds);
}
/// <summary> /// <summary>
/// Shows the given surface node by changing the view scale and the position and focuses the node. /// Shows the given surface node by changing the view scale and the position and focuses the node.
/// </summary> /// </summary>
@@ -1111,7 +1066,6 @@ namespace FlaxEditor.Surface
_cmPrimaryMenu?.Dispose(); _cmPrimaryMenu?.Dispose();
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin; ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
base.OnDestroy(); base.OnDestroy();
} }

View File

@@ -254,10 +254,9 @@ namespace FlaxEditor.Surface
public SurfaceParameter GetParameter(Guid id) public SurfaceParameter GetParameter(Guid id)
{ {
SurfaceParameter result = null; SurfaceParameter result = null;
var parameters = Parameters; for (int i = 0; i < Parameters.Count; i++)
for (int i = 0; i < parameters.Count; i++)
{ {
var parameter = parameters[i]; var parameter = Parameters[i];
if (parameter.ID == id) if (parameter.ID == id)
{ {
result = parameter; result = parameter;
@@ -275,10 +274,9 @@ namespace FlaxEditor.Surface
public SurfaceParameter GetParameter(string name) public SurfaceParameter GetParameter(string name)
{ {
SurfaceParameter result = null; SurfaceParameter result = null;
var parameters = Parameters; for (int i = 0; i < Parameters.Count; i++)
for (int i = 0; i < parameters.Count; i++)
{ {
var parameter = parameters[i]; var parameter = Parameters[i];
if (parameter.Name == name) if (parameter.Name == name)
{ {
result = parameter; result = parameter;

View File

@@ -187,9 +187,6 @@ namespace FlaxEditor.Surface
/// <inheritdoc /> /// <inheritdoc />
public override bool CanSetParameters => true; public override bool CanSetParameters => true;
/// <inheritdoc />
public override bool CanShowPrivateParameters => true;
/// <inheritdoc /> /// <inheritdoc />
public override bool UseContextMenuDescriptionPanel => true; public override bool UseContextMenuDescriptionPanel => true;

View File

@@ -89,7 +89,7 @@ namespace FlaxEditor.Tools.Terrain
if (!terrain.HasPatch(ref patchCoord) && _planeModel) if (!terrain.HasPatch(ref patchCoord) && _planeModel)
{ {
var planeSize = 100.0f; var planeSize = 100.0f;
var patchSize = terrain.PatchSize; var patchSize = terrain.ChunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
Matrix world = Matrix.RotationX(-Mathf.PiOverTwo) * Matrix world = Matrix.RotationX(-Mathf.PiOverTwo) *
Matrix.Scaling(patchSize / planeSize) * Matrix.Scaling(patchSize / planeSize) *
Matrix.Translation(patchSize * (0.5f + patchCoord.X), 0, patchSize * (0.5f + patchCoord.Y)) * Matrix.Translation(patchSize * (0.5f + patchCoord.X), 0, patchSize * (0.5f + patchCoord.Y)) *

View File

@@ -69,9 +69,9 @@ namespace FlaxEditor.Tools.Terrain.Paint
var splatmapIndex = ActiveSplatmapIndex; var splatmapIndex = ActiveSplatmapIndex;
var splatmapIndexOther = (splatmapIndex + 1) % 2; var splatmapIndexOther = (splatmapIndex + 1) % 2;
var chunkSize = terrain.ChunkSize; var chunkSize = terrain.ChunkSize;
var heightmapSize = terrain.HeightmapSize; var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
var heightmapLength = heightmapSize * heightmapSize; var heightmapLength = heightmapSize * heightmapSize;
var patchSize = terrain.PatchSize; var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, splatmapIndex).ToPointer(); var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, splatmapIndex).ToPointer();
var tempBufferOther = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, (splatmapIndex + 1) % 2).ToPointer(); var tempBufferOther = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, (splatmapIndex + 1) % 2).ToPointer();
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex; var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;

View File

@@ -70,9 +70,9 @@ namespace FlaxEditor.Tools.Terrain.Sculpt
// Prepare // Prepare
var chunkSize = terrain.ChunkSize; var chunkSize = terrain.ChunkSize;
var heightmapSize = terrain.HeightmapSize; var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
var heightmapLength = heightmapSize * heightmapSize; var heightmapLength = heightmapSize * heightmapSize;
var patchSize = terrain.PatchSize; var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
var tempBuffer = (float*)gizmo.GetHeightmapTempBuffer(heightmapLength * sizeof(float)).ToPointer(); var tempBuffer = (float*)gizmo.GetHeightmapTempBuffer(heightmapLength * sizeof(float)).ToPointer();
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex; var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;

View File

@@ -382,8 +382,7 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1; const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1;
Array<float> heightmap; Array<float> heightmap;
heightmap.Resize(heightmapSize.X * heightmapSize.Y); heightmap.Resize(heightmapSize.X * heightmapSize.Y);
if (const float* heightmapData = firstPatch->GetHeightmapData()) heightmap.SetAll(firstPatch->GetHeightmapData()[0]);
heightmap.SetAll(heightmapData[0]);
// Fill heightmap with data from all patches // Fill heightmap with data from all patches
const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
@@ -393,16 +392,8 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y); const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y);
const float* src = patch->GetHeightmapData(); const float* src = patch->GetHeightmapData();
float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1); float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1);
if (src) for (int32 row = 0; row < rowSize; row++)
{ Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float));
for (int32 row = 0; row < rowSize; row++)
Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float));
}
else
{
for (int32 row = 0; row < rowSize; row++)
Platform::MemoryClear(dst + row * heightmapSize.X, rowSize * sizeof(float));
}
} }
// Interpolate to 16-bit int // Interpolate to 16-bit int

View File

@@ -85,7 +85,8 @@ namespace FlaxEditor.Tools.Terrain.Undo
{ {
_terrain = terrain.ID; _terrain = terrain.ID;
_patches = new List<PatchData>(4); _patches = new List<PatchData>(4);
var heightmapSize = terrain.HeightmapSize; var chunkSize = terrain.ChunkSize;
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
_heightmapLength = heightmapSize * heightmapSize; _heightmapLength = heightmapSize * heightmapSize;
_heightmapDataSize = _heightmapLength * stride; _heightmapDataSize = _heightmapLength * stride;

View File

@@ -41,7 +41,7 @@ namespace FlaxEditor.Actions
ActionString = name; ActionString = name;
_pasteParent = pasteParent; _pasteParent = pasteParent;
_idsMapping = new Dictionary<Guid, Guid>(objectIds.Length); _idsMapping = new Dictionary<Guid, Guid>(objectIds.Length * 4);
for (int i = 0; i < objectIds.Length; i++) for (int i = 0; i < objectIds.Length; i++)
{ {
_idsMapping[objectIds[i]] = Guid.NewGuid(); _idsMapping[objectIds[i]] = Guid.NewGuid();
@@ -72,24 +72,13 @@ namespace FlaxEditor.Actions
/// <summary> /// <summary>
/// Links the broken parent reference (missing parent). By default links the actor to the first scene. /// Links the broken parent reference (missing parent). By default links the actor to the first scene.
/// </summary> /// </summary>
/// <param name="actorNode">The actor node.</param> /// <param name="actor">The actor.</param>
protected virtual void LinkBrokenParentReference(ActorNode actorNode) protected virtual void LinkBrokenParentReference(Actor actor)
{ {
// Link to the first scene root // Link to the first scene root
if (Level.ScenesCount == 0) if (Level.ScenesCount == 0)
throw new Exception("Failed to paste actor with a broken reference. No loaded scenes."); throw new Exception("Failed to paste actor with a broken reference. No loaded scenes.");
actorNode.Actor.SetParent(Level.GetScene(0), false); actor.SetParent(Level.GetScene(0), false);
}
/// <summary>
/// Checks if actor has a broken parent reference. For example, it's linked to the parent that is indie prefab editor while it should be pasted into scene.
/// </summary>
/// <param name="actorNode">The actor node.</param>
protected virtual void CheckBrokenParentReference(ActorNode actorNode)
{
// Ensure pasted object ends up on a scene
if (actorNode.Actor.Scene == null)
LinkBrokenParentReference(actorNode);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -114,13 +103,16 @@ namespace FlaxEditor.Actions
for (int i = 0; i < actors.Length; i++) for (int i = 0; i < actors.Length; i++)
{ {
var actor = actors[i]; var actor = actors[i];
// Check if has no parent linked (broken reference eg. old parent not existing)
if (actor.Parent == null)
{
LinkBrokenParentReference(actor);
}
var node = GetNode(actor.ID); var node = GetNode(actor.ID);
if (node is ActorNode actorNode) if (node is ActorNode actorNode)
{ {
// Check if has no parent linked (broken reference eg. old parent not existing)
if (actor.Parent == null)
LinkBrokenParentReference(actorNode);
nodes.Add(actorNode); nodes.Add(actorNode);
} }
} }
@@ -144,12 +136,6 @@ namespace FlaxEditor.Actions
nodeParents[i].Actor.SetParent(pasteParentNode.Actor, false); nodeParents[i].Actor.SetParent(pasteParentNode.Actor, false);
} }
} }
else
{
// Sanity check on pasted actor to ensure they end up i na proper context (scene editor or specific prefab editor)
foreach (var node in nodeParents)
CheckBrokenParentReference(node);
}
// Store previously looked up names and the results // Store previously looked up names and the results
Dictionary<string, bool> foundNamesResults = new(); Dictionary<string, bool> foundNamesResults = new();

View File

@@ -166,6 +166,7 @@ namespace FlaxEditor.Viewport
#endif #endif
// Input // Input
internal bool _disableInputUpdate; internal bool _disableInputUpdate;
private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown; private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
private Float2 _startPos; private Float2 _startPos;
@@ -1228,7 +1229,7 @@ namespace FlaxEditor.Viewport
/// Orients the viewport. /// Orients the viewport.
/// </summary> /// </summary>
/// <param name="orientation">The orientation.</param> /// <param name="orientation">The orientation.</param>
public void OrientViewport(Quaternion orientation) protected void OrientViewport(Quaternion orientation)
{ {
OrientViewport(ref orientation); OrientViewport(ref orientation);
} }
@@ -1237,7 +1238,7 @@ namespace FlaxEditor.Viewport
/// Orients the viewport. /// Orients the viewport.
/// </summary> /// </summary>
/// <param name="orientation">The orientation.</param> /// <param name="orientation">The orientation.</param>
public virtual void OrientViewport(ref Quaternion orientation) protected virtual void OrientViewport(ref Quaternion orientation)
{ {
if (ViewportCamera is FPSCamera fpsCamera) if (ViewportCamera is FPSCamera fpsCamera)
{ {

View File

@@ -1,19 +1,18 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Object = FlaxEngine.Object;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Gizmo; using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Options;
using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Modes; using FlaxEditor.Viewport.Modes;
using FlaxEditor.Viewport.Widgets;
using FlaxEditor.Windows; using FlaxEditor.Windows;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Gizmo; using FlaxEngine.Gizmo;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using Object = FlaxEngine.Object;
namespace FlaxEditor.Viewport namespace FlaxEditor.Viewport
{ {
@@ -27,7 +26,6 @@ namespace FlaxEditor.Viewport
private readonly ContextMenuButton _showGridButton; private readonly ContextMenuButton _showGridButton;
private readonly ContextMenuButton _showNavigationButton; private readonly ContextMenuButton _showNavigationButton;
private readonly ContextMenuButton _toggleGameViewButton; private readonly ContextMenuButton _toggleGameViewButton;
private readonly ContextMenuButton _showDirectionGizmoButton;
private SelectionOutline _customSelectionOutline; private SelectionOutline _customSelectionOutline;
/// <summary> /// <summary>
@@ -110,14 +108,13 @@ namespace FlaxEditor.Viewport
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
private EditorSpritesRenderer _editorSpritesRenderer; private EditorSpritesRenderer _editorSpritesRenderer;
private ViewportRubberBandSelector _rubberBandSelector; private ViewportRubberBandSelector _rubberBandSelector;
private DirectionGizmo _directionGizmo;
private bool _gameViewActive; private bool _gameViewActive;
private ViewFlags _preGameViewFlags; private ViewFlags _preGameViewFlags;
private ViewMode _preGameViewViewMode; private ViewMode _preGameViewViewMode;
private bool _gameViewWasGridShown; private bool _gameViewWasGridShown;
private bool _gameViewWasFpsCounterShown; private bool _gameViewWasFpsCounterShown;
private bool _gameViewWasNavigationShown; private bool _gameViewWasNagivationShown;
/// <summary> /// <summary>
/// Drag and drop handlers /// Drag and drop handlers
@@ -229,13 +226,6 @@ namespace FlaxEditor.Viewport
// Add rubber band selector // Add rubber band selector
_rubberBandSelector = new ViewportRubberBandSelector(this); _rubberBandSelector = new ViewportRubberBandSelector(this);
// Add direction gizmo
_directionGizmo = new DirectionGizmo(this)
{
AnchorPreset = AnchorPresets.TopRight,
Parent = this,
};
// Add grid // Add grid
Grid = new GridGizmo(this); Grid = new GridGizmo(this);
Grid.EnabledChanged += gizmo => _showGridButton.Icon = gizmo.Enabled ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; Grid.EnabledChanged += gizmo => _showGridButton.Icon = gizmo.Enabled ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
@@ -254,11 +244,6 @@ namespace FlaxEditor.Viewport
_showNavigationButton = ViewWidgetShowMenu.AddButton("Navigation", inputOptions.ToggleNavMeshVisibility, () => ShowNavigation = !ShowNavigation); _showNavigationButton = ViewWidgetShowMenu.AddButton("Navigation", inputOptions.ToggleNavMeshVisibility, () => ShowNavigation = !ShowNavigation);
_showNavigationButton.CloseMenuOnClick = false; _showNavigationButton.CloseMenuOnClick = false;
// Show direction gizmo widget
_showDirectionGizmoButton = ViewWidgetShowMenu.AddButton("Direction Gizmo", () => _directionGizmo.Visible = !_directionGizmo.Visible);
_showDirectionGizmoButton.AutoCheck = true;
_showDirectionGizmoButton.CloseMenuOnClick = false;
// Game View // Game View
ViewWidgetButtonMenu.AddSeparator(); ViewWidgetButtonMenu.AddSeparator();
_toggleGameViewButton = ViewWidgetButtonMenu.AddButton("Game View", inputOptions.ToggleGameView, ToggleGameView); _toggleGameViewButton = ViewWidgetButtonMenu.AddButton("Game View", inputOptions.ToggleGameView, ToggleGameView);
@@ -292,18 +277,6 @@ namespace FlaxEditor.Viewport
// Game View // Game View
InputActions.Add(options => options.ToggleGameView, ToggleGameView); InputActions.Add(options => options.ToggleGameView, ToggleGameView);
editor.Options.OptionsChanged += OnEditorOptionsChanged;
OnEditorOptionsChanged(editor.Options.Options);
}
private void OnEditorOptionsChanged(EditorOptions options)
{
_directionGizmo.Visible = options.Viewport.ShowDirectionGizmo;
_showDirectionGizmoButton.Checked = _directionGizmo.Visible;
_directionGizmo.Size = new Float2(DirectionGizmo.DefaultGizmoSize * options.Viewport.DirectionGizmoScale);
_directionGizmo.LocalX = -_directionGizmo.Size.X * 0.5f;
_directionGizmo.LocalY = _directionGizmo.Size.Y * 0.5f + ViewportWidgetsContainer.WidgetsHeight;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -541,14 +514,14 @@ namespace FlaxEditor.Viewport
_preGameViewViewMode = Task.ViewMode; _preGameViewViewMode = Task.ViewMode;
_gameViewWasGridShown = Grid.Enabled; _gameViewWasGridShown = Grid.Enabled;
_gameViewWasFpsCounterShown = ShowFpsCounter; _gameViewWasFpsCounterShown = ShowFpsCounter;
_gameViewWasNavigationShown = ShowNavigation; _gameViewWasNagivationShown = ShowNavigation;
} }
// Set flags & values // Set flags & values
Task.ViewFlags = _gameViewActive ? _preGameViewFlags : ViewFlags.DefaultGame; Task.ViewFlags = _gameViewActive ? _preGameViewFlags : ViewFlags.DefaultGame;
Task.ViewMode = _gameViewActive ? _preGameViewViewMode : ViewMode.Default; Task.ViewMode = _gameViewActive ? _preGameViewViewMode : ViewMode.Default;
ShowFpsCounter = _gameViewActive ? _gameViewWasFpsCounterShown : false; ShowFpsCounter = _gameViewActive ? _gameViewWasFpsCounterShown : false;
ShowNavigation = _gameViewActive ? _gameViewWasNavigationShown : false; ShowNavigation = _gameViewActive ? _gameViewWasNagivationShown : false;
Grid.Enabled = _gameViewActive ? _gameViewWasGridShown : false; Grid.Enabled = _gameViewActive ? _gameViewWasGridShown : false;
_gameViewActive = !_gameViewActive; _gameViewActive = !_gameViewActive;
@@ -674,7 +647,7 @@ namespace FlaxEditor.Viewport
} }
/// <inheritdoc /> /// <inheritdoc />
public override void OrientViewport(ref Quaternion orientation) protected override void OrientViewport(ref Quaternion orientation)
{ {
if (TransformGizmo.SelectedParents.Count != 0) if (TransformGizmo.SelectedParents.Count != 0)
FocusSelection(ref orientation); FocusSelection(ref orientation);

View File

@@ -681,7 +681,7 @@ namespace FlaxEditor.Viewport
} }
/// <inheritdoc /> /// <inheritdoc />
public override void OrientViewport(ref Quaternion orientation) protected override void OrientViewport(ref Quaternion orientation)
{ {
if (TransformGizmo.SelectedParents.Count != 0) if (TransformGizmo.SelectedParents.Count != 0)
FocusSelection(ref orientation); FocusSelection(ref orientation);

Some files were not shown because too many files have changed in this diff Show More