Compare commits
320 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3a18883ca | |||
| 98b42d3e2e | |||
| 71f30f18a6 | |||
| 9e74f3ae22 | |||
| f4f49f63bc | |||
| eaabd56cae | |||
| 3fc0a3dc84 | |||
| cf155a4df4 | |||
| 40d6e18e7e | |||
| 2cef368282 | |||
| 40d8d3b972 | |||
| 6eb738bc58 | |||
| 91629d7a28 | |||
| cfef59d851 | |||
| 5f3fc38de2 | |||
| 49bc7d3dcc | |||
| d0f7a04c58 | |||
| 297cdc5bfd | |||
| f61f35b259 | |||
| aa1b779463 | |||
| 359d4ba8ef | |||
| 6cf7d49a10 | |||
| d5075d845c | |||
| d99a92fd13 | |||
| 5b7a3f9700 | |||
| eba4b9bcc1 | |||
| d01990e3bb | |||
| 0db259e300 | |||
| ce905fbe86 | |||
| 5fb82dd290 | |||
| ea81ac6a71 | |||
| 88f751eda7 | |||
| 33115fca0c | |||
| 4e37aafe6a | |||
| 9a091799fc | |||
| b14d88f8f8 | |||
| da0dc7f11c | |||
| 98012eb192 | |||
| e9a1be481f | |||
| 5573f5bb4a | |||
| 822c25af7d | |||
| 70a540da4a | |||
| 201a1f0264 | |||
| 9aa4421bfd | |||
| d90a0aa3f4 | |||
| fc2d9a745f | |||
| 4e190c2e3c | |||
| 6dcfe32979 | |||
| 389bf89e2a | |||
| 31aafeb0d1 | |||
| f9799f8ef3 | |||
| 017e7cbc60 | |||
| 4eaac4ab2f | |||
| ddcb792767 | |||
| 8bcb984180 | |||
| 038a4e6f90 | |||
| 3799674b83 | |||
| 25246de791 | |||
| e76fffc95a | |||
| 06c56d0a4b | |||
| 6c32e4a842 | |||
| 84f6e2f90f | |||
| f77f8fbb39 | |||
| 15aaf5043a | |||
| b7f2196784 | |||
| d9b90c9520 | |||
| 719498e99b | |||
| 0beb389012 | |||
| e177aec5fa | |||
| a1ef635a2c | |||
| ca64867f3c | |||
| 027fcbfd36 | |||
| bec878cc11 | |||
| f0865c3989 | |||
| 9738fd4354 | |||
| d33bf2fa6a | |||
| 307129b4a1 | |||
| 6aea001e94 | |||
| 3a59cfcf20 | |||
| 385693afff | |||
| e7ef3ebef2 | |||
| c45d606f69 | |||
| 2555b07edf | |||
| d533cf554a | |||
| bc3107d1db | |||
| 3f5c92e2fa | |||
| 8d3cb8953c | |||
| 6fd34bf5cc | |||
| 0360f7786d | |||
| 3320c76e14 | |||
| e0de6744e2 | |||
| 7c53b1e99a | |||
| dd579eb099 | |||
| 0d8868e5bb | |||
| c0f0bd87aa | |||
| f7fb366233 | |||
| b2f49e2791 | |||
| b848c12802 | |||
| 45cb4eb66d | |||
| a42d54e401 | |||
| ab5534da7f | |||
| 05ea803582 | |||
| eaafb72ca9 | |||
| 4ceed361e2 | |||
| a9e1568edc | |||
| 348ed463fc | |||
| 618273977c | |||
| 13881c7d97 | |||
| 97a28d4431 | |||
| 46f82aabcd | |||
| c328eabd2a | |||
| 422fb34c69 | |||
| c7eaed6c65 | |||
| 418918920e | |||
| 930b1b978c | |||
| 95180f4aa9 | |||
| 0f14672e3b | |||
| 0fe9f6f439 | |||
| cc1e98db3c | |||
| 31ce41c5a4 | |||
| be90f47585 | |||
| ddaa5f9161 | |||
| dc7170c51e | |||
| 43ae0bcd4c | |||
| 252bb680fa | |||
| beab66e42e | |||
| c2c0ad8067 | |||
| 057d1fbcc6 | |||
| 626cde118b | |||
| 36daa38e0f | |||
| ed69f11121 | |||
| 9cd8c02911 | |||
| 7d70a15034 | |||
| 39a5b8e635 | |||
| 2ae290491e | |||
| 3c71dc99e0 | |||
| ea3f02f810 | |||
| 4ae57e7769 | |||
| 22c8ec5342 | |||
| 710b9275fd | |||
| e7844bb5b2 | |||
| d8a54692f0 | |||
| 30ca7d52d0 | |||
| 888a8ee7b9 | |||
| d90b723487 | |||
| 67c22cf3d4 | |||
| 6497f3109a | |||
| 6dcadb5131 | |||
| d6f449820b | |||
| a6c47ae17b | |||
| b3c15d6562 | |||
| 0fe46457c6 | |||
| bcaa42dda2 | |||
| 22fa7a89ac | |||
| e572f75b06 | |||
| 11b60390b6 | |||
| 1a7770fba2 | |||
| 966fb0275b | |||
| 785d3e8648 | |||
| 2f9343c236 | |||
| 52a1175f96 | |||
| 77b6a4a68b | |||
| 74bcf7d9e5 | |||
| 22d754e797 | |||
| 0d85094ebb | |||
| 7d43a0cc8b | |||
| 4c413cb146 | |||
| 4238c43f27 | |||
| f163edfb7e | |||
| fd4a5595c0 | |||
| f6645e5600 | |||
| b72849eafe | |||
| d6e93a7fab | |||
| 6648481d12 | |||
| 87a9dedba4 | |||
| 4fdeb773a5 | |||
| a90cf7c28f | |||
| 4b2595e904 | |||
| 42e8311736 | |||
| a685918e10 | |||
| 47ca4228dd | |||
| 7dc645c114 | |||
| c78ce9697c | |||
| c3d74b690e | |||
| ae85a94261 | |||
| e7b1fce3eb | |||
| b47420f232 | |||
| c025b4414c | |||
| 51c0a6e100 | |||
| 9a9e32d4c5 | |||
| 1e9ded55b0 | |||
| e22fa20dc1 | |||
| fe69a52cf2 | |||
| 9eb9294e84 | |||
| c53fce18a8 | |||
| 8500667817 | |||
| 40a3911453 | |||
| e57e86cde1 | |||
| ad290d0140 | |||
| 0930671e90 | |||
| 855122672f | |||
| e68330f5b5 | |||
| a0d4714a0f | |||
| f703e7de77 | |||
| 7e6c8b7b32 | |||
| a55dcf42da | |||
| 23369c2ff3 | |||
| 7855049509 | |||
| d79dd4aaf7 | |||
| 2c5a5acf33 | |||
| 342360f537 | |||
| 3ba8875121 | |||
| 655afb4b90 | |||
| f9a9912895 | |||
| bc91b1ed44 | |||
| 6fbf7fa07b | |||
| ea48056699 | |||
| 82d5130261 | |||
| b7e0994932 | |||
| d13b30304a | |||
| abc340b52c | |||
| 2dd16c1fb0 | |||
| 77e6aafc79 | |||
| c23f8f2b30 | |||
| 267e8daba5 | |||
| c5d3954bc8 | |||
| a7bb236344 | |||
| 0387f7df8a | |||
| ca2106ff5d | |||
| 4a10878b45 | |||
| 22e34cb2b4 | |||
| 585b6bacad | |||
| f736aae75d | |||
| 880e13865f | |||
| 7072839254 | |||
| 45060721e7 | |||
| 87d67a78f4 | |||
| 0ab43dd301 | |||
| 8c34fe7933 | |||
| fe3f64f06a | |||
| 8af3cfd90b | |||
| 3bf7b57dbd | |||
| 19752e4f3b | |||
| 50bcbf980e | |||
| 236e5772ce | |||
| 6ddf241ea4 | |||
| e429e85aae | |||
| 224e43ea55 | |||
| 6f1ee382b5 | |||
| da72dd4806 | |||
| 087cfd7a8c | |||
| 151c6bc6c3 | |||
| c0a8d29453 | |||
| 1a254afd4f | |||
| f6e9d0431b | |||
| 6cfc8c1b1a | |||
| 536be6c6cf | |||
| b0fe99f1ec | |||
| df5dc0c284 | |||
| f9614a4879 | |||
| 4e2ee897bc | |||
| 357148f973 | |||
| 1fa03a0de2 | |||
| 590f3f7493 | |||
| 90642b8862 | |||
| 900e6338d6 | |||
| 18c119c155 | |||
| 8c6ced4bb9 | |||
| 66a709f09e | |||
| bfaae46c7e | |||
| b8921fd990 | |||
| 73694cba6c | |||
| 1f8da14780 | |||
| cfe717969b | |||
| 210c5a5bb2 | |||
| 137c82a387 | |||
| b2db1330c0 | |||
| 06f37794c2 | |||
| 081648ef06 | |||
| 8982961254 | |||
| 2e85ff0fb3 | |||
| fbaf14b6fa | |||
| ea00a448ef | |||
| 7b2058d1b2 | |||
| ba31627ae0 | |||
| ec7840f36b | |||
| fa8b92a456 | |||
| 432f6d5402 | |||
| 571f8febf4 | |||
| c371a5b78c | |||
| 70ccc79d54 | |||
| 7cb4d27979 | |||
| fdda42e504 | |||
| 4efbed91a4 | |||
| ad6affc863 | |||
| aafdc64b68 | |||
| 41a7aff6d7 | |||
| 9bd002ea33 | |||
| 3afb6cc88e | |||
| b2ba40b082 | |||
| 2537855aa3 | |||
| 447030f53a | |||
| a96445d8bb | |||
| bcdd6c0551 | |||
| ff7e6d82f8 | |||
| 5b3e09baec | |||
| 0d7e7c30ca | |||
| dcec847d50 | |||
| 004e2ab5e8 | |||
| d7095957d0 | |||
| 4e2870e90c | |||
| 1736aaeb6a | |||
| d5c0ad0487 | |||
| d07a5e9823 | |||
| 329910ae0d | |||
| d7b9056d94 | |||
| 367eaf2f89 | |||
| 70ca1996c5 | |||
| b7b8213179 | |||
| ad28a3fdbf |
@@ -33,4 +33,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=ARM64 -platform=Android -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -33,4 +33,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=7 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-linux:
|
||||
@@ -64,4 +64,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Mac -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-mac:
|
||||
@@ -55,4 +55,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Mac -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
|
||||
# Game
|
||||
game-windows:
|
||||
@@ -55,4 +55,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -printSDKs -dotnet=7 -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
@@ -34,8 +34,8 @@ jobs:
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Build
|
||||
run: |
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=7
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=7 -arch=x64 -platform=Linux -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
|
||||
- name: Test
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
dotnet test -f net7.0 Binaries/Tests/FlaxEngine.CSharp.dll
|
||||
- name: Test UseLargeWorlds
|
||||
run: |
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
|
||||
./Development/Scripts/Linux/CallBuildTool.sh -build -log -dotnet=7 -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxTestsTarget -UseLargeWorlds=true
|
||||
${GITHUB_WORKSPACE}/Binaries/Editor/Linux/Development/FlaxTests
|
||||
|
||||
# Tests on Windows
|
||||
@@ -72,8 +72,8 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=7
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=7 -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
|
||||
- name: Test
|
||||
run: |
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-2
@@ -3,8 +3,8 @@
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 7,
|
||||
"Revision": 0,
|
||||
"Build": 6404
|
||||
"Revision": 1,
|
||||
"Build": 6406
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ pushd
|
||||
echo Performing the full package...
|
||||
|
||||
rem Run the build tool.
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -deployPlatforms -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -deployPlatforms -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
if errorlevel 1 goto BuildToolFailed
|
||||
|
||||
popd
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ pushd
|
||||
echo Building and packaging Flax Editor...
|
||||
|
||||
rem Run the build tool.
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployEditor -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
if errorlevel 1 goto BuildToolFailed
|
||||
|
||||
popd
|
||||
|
||||
@@ -9,4 +9,4 @@ echo Building and packaging Flax Editor...
|
||||
cd "`dirname "$0"`"
|
||||
|
||||
# Run Flax.Build (also pass the arguments)
|
||||
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployEditor --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployEditor --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ echo Building and packaging Flax Editor...
|
||||
cd "`dirname "$0"`"
|
||||
|
||||
# Run Flax.Build (also pass the arguments)
|
||||
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployEditor --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployEditor --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
|
||||
@@ -7,7 +7,7 @@ pushd
|
||||
echo Building and packaging platforms data...
|
||||
|
||||
rem Run the build tool.
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployPlatforms -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
call "Development\Scripts\Windows\CallBuildTool.bat" -deploy -deployPlatforms -dotnet=7 -verbose -log -logFile="Cache\Intermediate\PackageLog.txt" %*
|
||||
if errorlevel 1 goto BuildToolFailed
|
||||
|
||||
popd
|
||||
|
||||
@@ -9,4 +9,4 @@ echo Building and packaging platforms data...
|
||||
cd "`dirname "$0"`"
|
||||
|
||||
# Run Flax.Build (also pass the arguments)
|
||||
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployPlatforms --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
bash ./Development/Scripts/Mac/CallBuildTool.sh --deploy --deployPlatforms --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
|
||||
+1
-1
@@ -9,4 +9,4 @@ echo Building and packaging platforms data...
|
||||
cd "`dirname "$0"`"
|
||||
|
||||
# Run Flax.Build (also pass the arguments)
|
||||
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployPlatforms --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployPlatforms --dotnet=7 --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@"
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Content;
|
||||
|
||||
/// <summary>
|
||||
/// Manages and converts the selected content item to the appropriate types. Useful for drag operations.
|
||||
/// </summary>
|
||||
public class AssetPickerValidator : IContentItemOwner
|
||||
{
|
||||
private Asset _selected;
|
||||
private ContentItem _selectedItem;
|
||||
private ScriptType _type;
|
||||
private string _fileExtension;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item.
|
||||
/// </summary>
|
||||
public ContentItem SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
if (_selectedItem == value)
|
||||
return;
|
||||
if (value == null)
|
||||
{
|
||||
if (_selected == null && _selectedItem is SceneItem)
|
||||
{
|
||||
// Deselect scene reference
|
||||
_selectedItem.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deselect
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
else if (value is SceneItem item)
|
||||
{
|
||||
if (_selectedItem == item)
|
||||
return;
|
||||
if (!IsValid(item))
|
||||
item = null;
|
||||
|
||||
// Change value to scene reference (cannot load asset because scene can be already loaded - duplicated ID issue)
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = item;
|
||||
_selected = null;
|
||||
_selectedItem?.AddReference(this);
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
else if (value is AssetItem assetItem)
|
||||
{
|
||||
SelectedAsset = FlaxEngine.Content.LoadAsync(assetItem.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change value
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = value;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected asset identifier.
|
||||
/// </summary>
|
||||
public Guid SelectedID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selected != null)
|
||||
return _selected.ID;
|
||||
if (_selectedItem is AssetItem assetItem)
|
||||
return assetItem.ID;
|
||||
return Guid.Empty;
|
||||
}
|
||||
set => SelectedItem = Editor.Instance.ContentDatabase.FindAsset(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected content item path.
|
||||
/// </summary>
|
||||
public string SelectedPath
|
||||
{
|
||||
get
|
||||
{
|
||||
string path = _selectedItem?.Path ?? _selected?.Path;
|
||||
if (path != null)
|
||||
{
|
||||
// Convert into path relative to the project (cross-platform)
|
||||
var projectFolder = Globals.ProjectFolder;
|
||||
if (path.StartsWith(projectFolder))
|
||||
path = path.Substring(projectFolder.Length + 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = StringUtils.IsRelative(value) ? Path.Combine(Globals.ProjectFolder, value) : value;
|
||||
SelectedItem = Editor.Instance.ContentDatabase.Find(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected asset object.
|
||||
/// </summary>
|
||||
public Asset SelectedAsset
|
||||
{
|
||||
get => _selected;
|
||||
set
|
||||
{
|
||||
// Check if value won't change
|
||||
if (value == _selected)
|
||||
return;
|
||||
|
||||
// Find item from content database and check it
|
||||
var item = value ? Editor.Instance.ContentDatabase.FindAsset(value.ID) : null;
|
||||
if (item != null && !IsValid(item))
|
||||
item = null;
|
||||
|
||||
// Change value
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = item;
|
||||
_selected = value;
|
||||
_selectedItem?.AddReference(this);
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the assets types that this picker accepts (it supports types derived from the given type). Use <see cref="ScriptType.Null"/> for generic file picker.
|
||||
/// </summary>
|
||||
public ScriptType AssetType
|
||||
{
|
||||
get => _type;
|
||||
set
|
||||
{
|
||||
if (_type != value)
|
||||
{
|
||||
_type = value;
|
||||
|
||||
// Auto deselect if the current value is invalid
|
||||
if (_selectedItem != null && !IsValid(_selectedItem))
|
||||
SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content items extensions filter. Null if unused.
|
||||
/// </summary>
|
||||
public string FileExtension
|
||||
{
|
||||
get => _fileExtension;
|
||||
set
|
||||
{
|
||||
if (_fileExtension != value)
|
||||
{
|
||||
_fileExtension = value;
|
||||
|
||||
// Auto deselect if the current value is invalid
|
||||
if (_selectedItem != null && !IsValid(_selectedItem))
|
||||
SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when selected item gets changed.
|
||||
/// </summary>
|
||||
public event Action SelectedItemChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The custom callback for assets validation. Cane be used to implement a rule for assets to pick.
|
||||
/// </summary>
|
||||
public Func<ContentItem, bool> CheckValid;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether item is valid.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsValid(ContentItem item)
|
||||
{
|
||||
if (_fileExtension != null && !item.Path.EndsWith(_fileExtension))
|
||||
return false;
|
||||
if (CheckValid != null && !CheckValid(item))
|
||||
return false;
|
||||
if (_type == ScriptType.Null)
|
||||
return true;
|
||||
|
||||
if (item is AssetItem assetItem)
|
||||
{
|
||||
// Faster path for binary items (in-built)
|
||||
if (assetItem is BinaryAssetItem binaryItem)
|
||||
return _type.IsAssignableFrom(new ScriptType(binaryItem.Type));
|
||||
|
||||
// Type filter
|
||||
var type = TypeUtils.GetType(assetItem.TypeName);
|
||||
if (_type.IsAssignableFrom(type))
|
||||
return true;
|
||||
|
||||
// Json assets can contain any type of the object defined by the C# type (data oriented design)
|
||||
if (assetItem is JsonAssetItem && (_type.Type == typeof(JsonAsset) || _type.Type == typeof(Asset)))
|
||||
return true;
|
||||
|
||||
// Special case for scene asset references
|
||||
if (_type.Type == typeof(SceneReference) && assetItem is SceneItem)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetPickerValidator"/> class.
|
||||
/// </summary>
|
||||
public AssetPickerValidator()
|
||||
: this(new ScriptType(typeof(Asset)))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetPickerValidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="assetType">The assets types that this picker accepts.</param>
|
||||
public AssetPickerValidator(ScriptType assetType)
|
||||
{
|
||||
_type = assetType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when selected item gets changed.
|
||||
/// </summary>
|
||||
protected virtual void OnSelectedItemChanged()
|
||||
{
|
||||
SelectedItemChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDeleted(ContentItem item)
|
||||
{
|
||||
// Deselect item
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemRenamed(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemReimported(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDispose(ContentItem item)
|
||||
{
|
||||
// Deselect item
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to remove reference from the selected item.
|
||||
/// </summary>
|
||||
public void OnDestroy()
|
||||
{
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,7 @@ namespace FlaxEditor.Content
|
||||
Folder.ParentFolder = parent.Folder;
|
||||
Parent = parent;
|
||||
}
|
||||
IconColor = Style.Current.Foreground;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
class GameCooker;
|
||||
class PlatformTools;
|
||||
|
||||
#if OFFICIAL_BUILD
|
||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("-dotnet=7")
|
||||
#else
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("")
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Game building options. Used as flags.
|
||||
/// </summary>
|
||||
|
||||
@@ -280,17 +280,25 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
const Char* gradlew = TEXT("gradlew");
|
||||
#endif
|
||||
#if PLATFORM_LINUX
|
||||
Platform::RunProcess(String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath), data.OriginalOutputPath, Dictionary<String, String>(), true);
|
||||
{
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("chmod +x \"{0}/gradlew\""), data.OriginalOutputPath);
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
procSettings.HiddenWindow = true;
|
||||
Platform::CreateProcess(procSettings);
|
||||
}
|
||||
#endif
|
||||
const bool distributionPackage = buildSettings->ForDistribution;
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy result package
|
||||
|
||||
@@ -188,8 +188,8 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
LOG(Info, "Starting scripts compilation for game...");
|
||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||
auto args = String::Format(
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5}"),
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()));
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), GAME_BUILD_DOTNET_VER);
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
#elif PLATFORM_LINUX
|
||||
|
||||
@@ -87,7 +87,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
// Ask Flax.Build to provide .Net SDK location for the current platform
|
||||
String sdks;
|
||||
bool failed = ScriptsBuilder::RunBuildTool(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs"), data.CacheDirectory);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), GAME_BUILD_DOTNET_VER), data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||
if (idx != -1)
|
||||
@@ -168,7 +168,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
String sdks;
|
||||
const Char *platformName, *archName;
|
||||
data.GetBuildPlatformName(platformName, archName);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={}"), platformName, archName);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, GAME_BUILD_DOTNET_VER);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
Array<String> parts;
|
||||
@@ -269,8 +269,8 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
LOG(Info, "Optimizing .NET class library size to include only used assemblies");
|
||||
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\""),
|
||||
logFile, data.DataOutputPath);
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
|
||||
logFile, data.DataOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
|
||||
@@ -67,8 +67,8 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
data.GetBuildPlatformName(platform, architecture);
|
||||
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\""),
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath);
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||
for (const String& define : data.CustomDefines)
|
||||
|
||||
@@ -157,6 +157,12 @@ namespace FlaxEditor.CustomEditors
|
||||
var values = _values;
|
||||
var presenter = _presenter;
|
||||
var layout = _layout;
|
||||
if (layout.Editors.Count > 1)
|
||||
{
|
||||
// There are more editors using the same layout so rebuild parent editor to prevent removing others editors
|
||||
_parent?.RebuildLayout();
|
||||
return;
|
||||
}
|
||||
var control = layout.ContainerControl;
|
||||
var parent = _parent;
|
||||
var parentScrollV = (_presenter?.Panel.Parent as Panel)?.VScrollBar?.Value ?? -1;
|
||||
|
||||
@@ -225,8 +225,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
}
|
||||
_actor = actor;
|
||||
|
||||
var showActorPicker = actor == null || ParentEditor.Values.All(x => x is not Cloth);
|
||||
if (showActorPicker)
|
||||
if (ParentEditor.Values.Any(x => x is Cloth))
|
||||
{
|
||||
// Cloth always picks the parent model mesh
|
||||
if (actor == null)
|
||||
{
|
||||
layout.Label("Cloth needs to be added as a child to model actor.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Actor reference picker
|
||||
_actorPicker = layout.Custom<FlaxObjectRefPickerControl>();
|
||||
@@ -242,7 +249,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
var model = staticModel.Model;
|
||||
if (model == null || model.WaitForLoaded())
|
||||
{
|
||||
layout.Label("No model.");
|
||||
return;
|
||||
}
|
||||
var materials = model.MaterialSlots;
|
||||
var lods = model.LODs;
|
||||
meshNames = new string[lods.Length][];
|
||||
@@ -267,7 +277,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
var skinnedModel = animatedModel.SkinnedModel;
|
||||
if (skinnedModel == null || skinnedModel.WaitForLoaded())
|
||||
{
|
||||
layout.Label("No model.");
|
||||
return;
|
||||
}
|
||||
var materials = skinnedModel.MaterialSlots;
|
||||
var lods = skinnedModel.LODs;
|
||||
meshNames = new string[lods.Length][];
|
||||
|
||||
@@ -37,41 +37,32 @@ public class MissingScriptEditor : GenericEditor
|
||||
Parent = _dropPanel,
|
||||
Height = 64,
|
||||
};
|
||||
|
||||
_replaceScriptButton = new Button
|
||||
{
|
||||
Text = "Replace Script",
|
||||
TooltipText = "Replaces the missing script with a given script type",
|
||||
AnchorPreset = AnchorPresets.TopCenter,
|
||||
Width = 240,
|
||||
Height = 24,
|
||||
X = -120,
|
||||
Y = 0,
|
||||
Bounds = new Rectangle(-120, 0, 240, 24),
|
||||
Parent = replaceScriptPanel,
|
||||
};
|
||||
_replaceScriptButton.Clicked += OnReplaceScriptButtonClicked;
|
||||
|
||||
var replaceAllLabel = new Label
|
||||
{
|
||||
Text = "Replace all matching missing scripts",
|
||||
TooltipText = "Whether or not to apply this script change to all scripts missing the same type.",
|
||||
AnchorPreset = AnchorPresets.BottomCenter,
|
||||
Y = -34,
|
||||
Y = -38,
|
||||
Parent = replaceScriptPanel,
|
||||
};
|
||||
replaceAllLabel.X -= FlaxEngine.GUI.Style.Current.FontSmall.MeasureText(replaceAllLabel.Text).X;
|
||||
|
||||
_shouldReplaceAllCheckbox = new CheckBox
|
||||
{
|
||||
TooltipText = replaceAllLabel.TooltipText,
|
||||
AnchorPreset = AnchorPresets.BottomCenter,
|
||||
Y = -34,
|
||||
Y = -38,
|
||||
Parent = replaceScriptPanel,
|
||||
};
|
||||
|
||||
float centerDifference = (_shouldReplaceAllCheckbox.Right - replaceAllLabel.Left) / 2;
|
||||
replaceAllLabel.X += centerDifference;
|
||||
_shouldReplaceAllCheckbox.X += centerDifference;
|
||||
_shouldReplaceAllCheckbox.X -= _replaceScriptButton.Width * 0.5f + 0.5f;
|
||||
replaceAllLabel.X -= 52;
|
||||
|
||||
base.Initialize(layout);
|
||||
}
|
||||
|
||||
@@ -695,7 +695,41 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private void SetType(ref ScriptType controlType, UIControl uiControl)
|
||||
{
|
||||
string previousName = uiControl.Control?.GetType().Name ?? nameof(UIControl);
|
||||
uiControl.Control = (Control)controlType.CreateInstance();
|
||||
|
||||
var oldControlType = (Control)uiControl.Control;
|
||||
var newControlType = (Control)controlType.CreateInstance();
|
||||
|
||||
// copy old control data to new control
|
||||
if (oldControlType != null)
|
||||
{
|
||||
newControlType.Visible = oldControlType.Visible;
|
||||
newControlType.Enabled = oldControlType.Enabled;
|
||||
newControlType.AutoFocus = oldControlType.AutoFocus;
|
||||
|
||||
newControlType.AnchorMin = oldControlType.AnchorMin;
|
||||
newControlType.AnchorMax = oldControlType.AnchorMax;
|
||||
newControlType.Offsets = oldControlType.Offsets;
|
||||
|
||||
newControlType.LocalLocation = oldControlType.LocalLocation;
|
||||
newControlType.Scale = oldControlType.Scale;
|
||||
newControlType.Bounds = oldControlType.Bounds;
|
||||
newControlType.Width = oldControlType.Width;
|
||||
newControlType.Height = oldControlType.Height;
|
||||
newControlType.Center = oldControlType.Center;
|
||||
newControlType.PivotRelative = oldControlType.PivotRelative;
|
||||
|
||||
newControlType.Pivot = oldControlType.Pivot;
|
||||
newControlType.Shear = oldControlType.Shear;
|
||||
newControlType.Rotation = oldControlType.Rotation;
|
||||
}
|
||||
if (oldControlType is ContainerControl oldContainer && newControlType is ContainerControl newContainer)
|
||||
{
|
||||
newContainer.CullChildren = oldContainer.CullChildren;
|
||||
newContainer.ClipChildren = oldContainer.ClipChildren;
|
||||
}
|
||||
|
||||
uiControl.Control = newControlType;
|
||||
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
value = 0;
|
||||
|
||||
// If selected is single actor that has children, ask if apply layer to the sub objects as well
|
||||
if (Values.IsSingleObject && (int)Values[0] != value && ParentEditor.Values[0] is Actor actor && actor.HasChildren)
|
||||
if (Values.IsSingleObject && (int)Values[0] != value && ParentEditor.Values[0] is Actor actor && actor.HasChildren && !Editor.IsPlayMode)
|
||||
{
|
||||
var valueText = comboBox.SelectedItem;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
// Generic file picker
|
||||
assetType = ScriptType.Null;
|
||||
Picker.FileExtension = assetReference.TypeName;
|
||||
Picker.Validator.FileExtension = assetReference.TypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -85,7 +85,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
Picker.AssetType = assetType;
|
||||
Picker.Validator.AssetType = assetType;
|
||||
Picker.Height = height;
|
||||
Picker.SelectedItemChanged += OnSelectedItemChanged;
|
||||
}
|
||||
@@ -95,15 +95,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
if (typeof(AssetItem).IsAssignableFrom(_valueType.Type))
|
||||
SetValue(Picker.SelectedItem);
|
||||
SetValue(Picker.Validator.SelectedItem);
|
||||
else if (_valueType.Type == typeof(Guid))
|
||||
SetValue(Picker.SelectedID);
|
||||
SetValue(Picker.Validator.SelectedID);
|
||||
else if (_valueType.Type == typeof(SceneReference))
|
||||
SetValue(new SceneReference(Picker.SelectedID));
|
||||
SetValue(new SceneReference(Picker.Validator.SelectedID));
|
||||
else if (_valueType.Type == typeof(string))
|
||||
SetValue(Picker.SelectedPath);
|
||||
SetValue(Picker.Validator.SelectedPath);
|
||||
else
|
||||
SetValue(Picker.SelectedAsset);
|
||||
SetValue(Picker.Validator.SelectedAsset);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -115,15 +115,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
_isRefreshing = true;
|
||||
if (Values[0] is AssetItem assetItem)
|
||||
Picker.SelectedItem = assetItem;
|
||||
Picker.Validator.SelectedItem = assetItem;
|
||||
else if (Values[0] is Guid guid)
|
||||
Picker.SelectedID = guid;
|
||||
Picker.Validator.SelectedID = guid;
|
||||
else if (Values[0] is SceneReference sceneAsset)
|
||||
Picker.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
||||
Picker.Validator.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
||||
else if (Values[0] is string path)
|
||||
Picker.SelectedPath = path;
|
||||
Picker.Validator.SelectedPath = path;
|
||||
else
|
||||
Picker.SelectedAsset = Values[0] as Asset;
|
||||
Picker.Validator.SelectedAsset = Values[0] as Asset;
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,11 +171,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
tree.Select(typeNode);
|
||||
if (addItems)
|
||||
{
|
||||
var items = GenericEditor.GetItemsForType(type, type.IsClass, true);
|
||||
var items = GenericEditor.GetItemsForType(type, type.IsClass, true, true);
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (typed && !typed.IsAssignableFrom(item.Info.ValueType))
|
||||
continue;
|
||||
if (item.Info.DeclaringType.Type == typeof(FlaxEngine.Object))
|
||||
continue; // Skip engine internals
|
||||
var itemPath = typePath + item.Info.Name;
|
||||
var node = new TreeNode
|
||||
{
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -110,7 +113,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
// No support for different collections for now
|
||||
if (HasDifferentValues || HasDifferentTypes)
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
|
||||
var size = Count;
|
||||
@@ -135,14 +138,43 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
spacing = collection.Spacing;
|
||||
}
|
||||
|
||||
var dragArea = layout.CustomContainer<DragAreaControl>();
|
||||
dragArea.CustomControl.Editor = this;
|
||||
dragArea.CustomControl.ElementType = ElementType;
|
||||
|
||||
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter
|
||||
// which scripts can be dragged over and dropped on this collection editor.
|
||||
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
|
||||
if (assetReference != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetReference.TypeName))
|
||||
{
|
||||
}
|
||||
else if (assetReference.TypeName.Length > 1 && assetReference.TypeName[0] == '.')
|
||||
{
|
||||
dragArea.CustomControl.ElementType = ScriptType.Null;
|
||||
dragArea.CustomControl.FileExtension = assetReference.TypeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var customType = TypeUtils.GetType(assetReference.TypeName);
|
||||
if (customType != ScriptType.Null)
|
||||
dragArea.CustomControl.ElementType = customType;
|
||||
else if (!Content.Settings.GameSettings.OptionalPlatformSettings.Contains(assetReference.TypeName))
|
||||
Debug.LogWarning(string.Format("Unknown asset type '{0}' to use for drag and drop filter.", assetReference.TypeName));
|
||||
else
|
||||
dragArea.CustomControl.ElementType = ScriptType.Void;
|
||||
}
|
||||
}
|
||||
|
||||
// Size
|
||||
if (_readOnly || (NotNullItems && size == 0))
|
||||
{
|
||||
layout.Label("Size", size.ToString());
|
||||
dragArea.Label("Size", size.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_size = layout.IntegerValue("Size");
|
||||
_size = dragArea.IntegerValue("Size");
|
||||
_size.IntValue.MinValue = 0;
|
||||
_size.IntValue.MaxValue = ushort.MaxValue;
|
||||
_size.IntValue.Value = size;
|
||||
@@ -152,7 +184,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Elements
|
||||
if (size > 0)
|
||||
{
|
||||
var panel = layout.VerticalPanel();
|
||||
var panel = dragArea.VerticalPanel();
|
||||
panel.Panel.BackgroundColor = _background;
|
||||
var elementType = ElementType;
|
||||
|
||||
@@ -212,37 +244,33 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Add/Remove buttons
|
||||
if (!_readOnly)
|
||||
{
|
||||
var area = layout.Space(20);
|
||||
var addButton = new Button(area.ContainerControl.Width - (16 + 16 + 2 + 2), 2, 16, 16)
|
||||
{
|
||||
Text = "+",
|
||||
TooltipText = "Add new item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = !NotNullItems || size > 0,
|
||||
};
|
||||
addButton.Clicked += () =>
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
var panel = dragArea.HorizontalPanel();
|
||||
panel.Panel.Size = new Float2(0, 20);
|
||||
panel.Panel.Margin = new Margin(2);
|
||||
|
||||
Resize(Count + 1);
|
||||
};
|
||||
var removeButton = new Button(addButton.Right + 2, addButton.Y, 16, 16)
|
||||
{
|
||||
Text = "-",
|
||||
TooltipText = "Remove last item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = size > 0,
|
||||
};
|
||||
removeButton.Clicked += () =>
|
||||
var removeButton = panel.Button("-", "Remove last item");
|
||||
removeButton.Button.Size = new Float2(16, 16);
|
||||
removeButton.Button.Enabled = size > 0;
|
||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
removeButton.Button.Clicked += () =>
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
Resize(Count - 1);
|
||||
};
|
||||
|
||||
var addButton = panel.Button("+", "Add new item");
|
||||
addButton.Button.Size = new Float2(16, 16);
|
||||
addButton.Button.Enabled = !NotNullItems || size > 0;
|
||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
addButton.Button.Clicked += () =>
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
Resize(Count + 1);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,5 +397,232 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
return base.OnDirty(editor, value, token);
|
||||
}
|
||||
|
||||
private class DragAreaControl : VerticalPanel
|
||||
{
|
||||
private DragItems _dragItems;
|
||||
private DragActors _dragActors;
|
||||
private DragHandlers _dragHandlers;
|
||||
private AssetPickerValidator _pickerValidator;
|
||||
|
||||
public ScriptType ElementType
|
||||
{
|
||||
get => _pickerValidator?.AssetType ?? ScriptType.Null;
|
||||
set => _pickerValidator = new AssetPickerValidator(value);
|
||||
}
|
||||
|
||||
public CollectionEditor Editor { get; set; }
|
||||
|
||||
public string FileExtension
|
||||
{
|
||||
set => _pickerValidator.FileExtension = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
if (_dragHandlers is { HasValidDrag: true })
|
||||
{
|
||||
var area = new Rectangle(Float2.Zero, Size);
|
||||
Render2D.FillRectangle(area, Color.Orange * 0.5f);
|
||||
Render2D.DrawRectangle(area, Color.Black);
|
||||
}
|
||||
|
||||
base.Draw();
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_pickerValidator.OnDestroy();
|
||||
}
|
||||
|
||||
private bool ValidateActors(ActorNode node)
|
||||
{
|
||||
return node.Actor.GetScript(ElementType.Type) || ElementType.Type.IsAssignableTo(typeof(Actor));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = base.OnDragEnter(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
if (_dragHandlers == null)
|
||||
{
|
||||
_dragItems = new DragItems(_pickerValidator.IsValid);
|
||||
_dragActors = new DragActors(ValidateActors);
|
||||
_dragHandlers = new DragHandlers
|
||||
{
|
||||
_dragActors,
|
||||
_dragItems
|
||||
};
|
||||
}
|
||||
return _dragHandlers.OnDragEnter(data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
return _dragHandlers.Effect;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragHandlers.OnDragLeave();
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = base.OnDragDrop(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
{
|
||||
_dragHandlers.OnDragDrop(null);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_dragHandlers.HasValidDrag)
|
||||
{
|
||||
if (_dragItems.HasValidDrag)
|
||||
{
|
||||
var list = Editor.CloneValues();
|
||||
if (list == null)
|
||||
{
|
||||
if (Editor.Values.Type.IsArray)
|
||||
{
|
||||
list = TypeUtils.CreateArrayInstance(Editor.Values.Type.GetElementType(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = Editor.Values.Type.CreateInstance() as IList;
|
||||
}
|
||||
}
|
||||
if (list.IsFixedSize)
|
||||
{
|
||||
var oldSize = list.Count;
|
||||
var newSize = list.Count + _dragItems.Objects.Count;
|
||||
var type = Editor.Values.Type.GetElementType();
|
||||
var array = TypeUtils.CreateArrayInstance(type, newSize);
|
||||
list.CopyTo(array, 0);
|
||||
|
||||
for (var i = oldSize; i < newSize; i++)
|
||||
{
|
||||
var validator = new AssetPickerValidator
|
||||
{
|
||||
FileExtension = _pickerValidator.FileExtension,
|
||||
AssetType = _pickerValidator.AssetType,
|
||||
SelectedItem = _dragItems.Objects[i - oldSize],
|
||||
};
|
||||
|
||||
if (typeof(AssetItem).IsAssignableFrom(ElementType.Type))
|
||||
array.SetValue(validator.SelectedItem, i);
|
||||
else if (ElementType.Type == typeof(Guid))
|
||||
array.SetValue(validator.SelectedID, i);
|
||||
else if (ElementType.Type == typeof(SceneReference))
|
||||
array.SetValue(new SceneReference(validator.SelectedID), i);
|
||||
else if (ElementType.Type == typeof(string))
|
||||
array.SetValue(validator.SelectedPath, i);
|
||||
else
|
||||
array.SetValue(validator.SelectedAsset, i);
|
||||
|
||||
validator.OnDestroy();
|
||||
}
|
||||
Editor.SetValue(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in _dragItems.Objects)
|
||||
{
|
||||
var validator = new AssetPickerValidator
|
||||
{
|
||||
FileExtension = _pickerValidator.FileExtension,
|
||||
AssetType = _pickerValidator.AssetType,
|
||||
SelectedItem = item,
|
||||
};
|
||||
|
||||
if (typeof(AssetItem).IsAssignableFrom(ElementType.Type))
|
||||
list.Add(validator.SelectedItem);
|
||||
else if (ElementType.Type == typeof(Guid))
|
||||
list.Add(validator.SelectedID);
|
||||
else if (ElementType.Type == typeof(SceneReference))
|
||||
list.Add(new SceneReference(validator.SelectedID));
|
||||
else if (ElementType.Type == typeof(string))
|
||||
list.Add(validator.SelectedPath);
|
||||
else
|
||||
list.Add(validator.SelectedAsset);
|
||||
|
||||
validator.OnDestroy();
|
||||
}
|
||||
Editor.SetValue(list);
|
||||
}
|
||||
}
|
||||
else if (_dragActors.HasValidDrag)
|
||||
{
|
||||
var list = Editor.CloneValues();
|
||||
if (list == null)
|
||||
{
|
||||
if (Editor.Values.Type.IsArray)
|
||||
{
|
||||
list = TypeUtils.CreateArrayInstance(Editor.Values.Type.GetElementType(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = Editor.Values.Type.CreateInstance() as IList;
|
||||
}
|
||||
}
|
||||
|
||||
if (list.IsFixedSize)
|
||||
{
|
||||
var oldSize = list.Count;
|
||||
var newSize = list.Count + _dragActors.Objects.Count;
|
||||
var type = Editor.Values.Type.GetElementType();
|
||||
var array = TypeUtils.CreateArrayInstance(type, newSize);
|
||||
list.CopyTo(array, 0);
|
||||
|
||||
for (var i = oldSize; i < newSize; i++)
|
||||
{
|
||||
var actor = _dragActors.Objects[i - oldSize].Actor;
|
||||
if (ElementType.Type.IsAssignableTo(typeof(Actor)))
|
||||
{
|
||||
array.SetValue(actor, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
array.SetValue(actor.GetScript(ElementType.Type), i);
|
||||
}
|
||||
}
|
||||
Editor.SetValue(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var actorNode in _dragActors.Objects)
|
||||
{
|
||||
if (ElementType.Type.IsAssignableTo(typeof(Actor)))
|
||||
{
|
||||
list.Add(actorNode.Actor);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(actorNode.Actor.GetScript(ElementType.Type));
|
||||
}
|
||||
}
|
||||
Editor.SetValue(list);
|
||||
}
|
||||
}
|
||||
|
||||
_dragHandlers.OnDragDrop(null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,8 +247,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="useProperties">True if use type properties.</param>
|
||||
/// <param name="useFields">True if use type fields.</param>
|
||||
/// <param name="usePropertiesWithoutSetter">True if use type properties that have only getter method without setter method (aka read-only).</param>
|
||||
/// <returns>The items.</returns>
|
||||
public static List<ItemInfo> GetItemsForType(ScriptType type, bool useProperties, bool useFields)
|
||||
public static List<ItemInfo> GetItemsForType(ScriptType type, bool useProperties, bool useFields, bool usePropertiesWithoutSetter = false)
|
||||
{
|
||||
var items = new List<ItemInfo>();
|
||||
|
||||
@@ -264,7 +265,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var showInEditor = attributes.Any(x => x is ShowInEditorAttribute);
|
||||
|
||||
// Skip properties without getter or setter
|
||||
if (!p.HasGet || (!p.HasSet && !showInEditor))
|
||||
if (!p.HasGet || (!p.HasSet && !showInEditor && !usePropertiesWithoutSetter))
|
||||
continue;
|
||||
|
||||
// Skip hidden fields, handle special attributes
|
||||
|
||||
@@ -28,14 +28,16 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var group = layout.Group("Entry");
|
||||
_group = group;
|
||||
|
||||
if (ParentEditor == null)
|
||||
if (ParentEditor == null || HasDifferentTypes)
|
||||
return;
|
||||
var entry = (ModelInstanceEntry)Values[0];
|
||||
var entryIndex = ParentEditor.ChildrenEditors.IndexOf(this);
|
||||
var materialLabel = new PropertyNameLabel("Material");
|
||||
materialLabel.TooltipText = "The mesh surface material used for the rendering.";
|
||||
if (ParentEditor.ParentEditor?.Values[0] is ModelInstanceActor modelInstance)
|
||||
var parentEditorValues = ParentEditor.ParentEditor?.Values;
|
||||
if (parentEditorValues?[0] is ModelInstanceActor modelInstance)
|
||||
{
|
||||
// TODO: store _modelInstance and _material in array for each selected model instance actor
|
||||
_entryIndex = entryIndex;
|
||||
_modelInstance = modelInstance;
|
||||
var slots = modelInstance.MaterialSlots;
|
||||
@@ -56,6 +58,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Create material picker
|
||||
var materialValue = new CustomValueContainer(new ScriptType(typeof(MaterialBase)), _material, (instance, index) => _material, (instance, index, value) => _material = value as MaterialBase);
|
||||
for (var i = 1; i < parentEditorValues.Count; i++)
|
||||
materialValue.Add(_material);
|
||||
var materialEditor = (AssetRefEditor)_group.Property(materialLabel, materialValue);
|
||||
materialEditor.Values.SetDefaultValue(defaultValue);
|
||||
materialEditor.RefreshDefaultValue();
|
||||
@@ -72,14 +76,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return;
|
||||
_isRefreshing = true;
|
||||
var slots = _modelInstance.MaterialSlots;
|
||||
var material = _materialEditor.Picker.SelectedAsset as MaterialBase;
|
||||
var material = _materialEditor.Picker.Validator.SelectedAsset as MaterialBase;
|
||||
var defaultMaterial = GPUDevice.Instance.DefaultMaterial;
|
||||
var value = (ModelInstanceEntry)Values[0];
|
||||
var prevMaterial = value.Material;
|
||||
if (!material)
|
||||
{
|
||||
// Fallback to default material
|
||||
_materialEditor.Picker.SelectedAsset = defaultMaterial;
|
||||
_materialEditor.Picker.Validator.SelectedAsset = defaultMaterial;
|
||||
value.Material = defaultMaterial;
|
||||
}
|
||||
else if (material == slots[_entryIndex].Material)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.IO;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
@@ -17,189 +18,21 @@ namespace FlaxEditor.GUI
|
||||
/// <seealso cref="Control" />
|
||||
/// <seealso cref="IContentItemOwner" />
|
||||
[HideInEditor]
|
||||
public class AssetPicker : Control, IContentItemOwner
|
||||
public class AssetPicker : Control
|
||||
{
|
||||
private const float DefaultIconSize = 64;
|
||||
private const float ButtonsOffset = 2;
|
||||
private const float ButtonsSize = 12;
|
||||
|
||||
private Asset _selected;
|
||||
private ContentItem _selectedItem;
|
||||
private ScriptType _type;
|
||||
private string _fileExtension;
|
||||
|
||||
private bool _isMouseDown;
|
||||
private Float2 _mouseDownPos;
|
||||
private Float2 _mousePos;
|
||||
private DragItems _dragOverElement;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected item.
|
||||
/// The asset validator. Used to ensure only appropriate items can be picked.
|
||||
/// </summary>
|
||||
public ContentItem SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
if (_selectedItem == value)
|
||||
return;
|
||||
if (value == null)
|
||||
{
|
||||
if (_selected == null && _selectedItem is SceneItem)
|
||||
{
|
||||
// Deselect scene reference
|
||||
_selectedItem.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deselect
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
else if (value is SceneItem item)
|
||||
{
|
||||
if (_selectedItem == item)
|
||||
return;
|
||||
if (!IsValid(item))
|
||||
item = null;
|
||||
|
||||
// Change value to scene reference (cannot load asset because scene can be already loaded - duplicated ID issue)
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = item;
|
||||
_selected = null;
|
||||
_selectedItem?.AddReference(this);
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
else if (value is AssetItem assetItem)
|
||||
{
|
||||
SelectedAsset = FlaxEngine.Content.LoadAsync(assetItem.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change value
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = value;
|
||||
_selected = null;
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected asset identifier.
|
||||
/// </summary>
|
||||
public Guid SelectedID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selected != null)
|
||||
return _selected.ID;
|
||||
if (_selectedItem is AssetItem assetItem)
|
||||
return assetItem.ID;
|
||||
return Guid.Empty;
|
||||
}
|
||||
set => SelectedItem = Editor.Instance.ContentDatabase.FindAsset(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected content item path.
|
||||
/// </summary>
|
||||
public string SelectedPath
|
||||
{
|
||||
get
|
||||
{
|
||||
string path = _selectedItem?.Path ?? _selected?.Path;
|
||||
if (path != null)
|
||||
{
|
||||
// Convert into path relative to the project (cross-platform)
|
||||
var projectFolder = Globals.ProjectFolder;
|
||||
if (path.StartsWith(projectFolder))
|
||||
path = path.Substring(projectFolder.Length + 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = StringUtils.IsRelative(value) ? Path.Combine(Globals.ProjectFolder, value) : value;
|
||||
SelectedItem = Editor.Instance.ContentDatabase.Find(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected asset object.
|
||||
/// </summary>
|
||||
public Asset SelectedAsset
|
||||
{
|
||||
get => _selected;
|
||||
set
|
||||
{
|
||||
// Check if value won't change
|
||||
if (value == _selected)
|
||||
return;
|
||||
|
||||
// Find item from content database and check it
|
||||
var item = value ? Editor.Instance.ContentDatabase.FindAsset(value.ID) : null;
|
||||
if (item != null && !IsValid(item))
|
||||
item = null;
|
||||
|
||||
// Change value
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = item;
|
||||
_selected = value;
|
||||
_selectedItem?.AddReference(this);
|
||||
OnSelectedItemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the assets types that this picker accepts (it supports types derived from the given type). Use <see cref="ScriptType.Null"/> for generic file picker.
|
||||
/// </summary>
|
||||
public ScriptType AssetType
|
||||
{
|
||||
get => _type;
|
||||
set
|
||||
{
|
||||
if (_type != value)
|
||||
{
|
||||
_type = value;
|
||||
|
||||
// Auto deselect if the current value is invalid
|
||||
if (_selectedItem != null && !IsValid(_selectedItem))
|
||||
SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content items extensions filter. Null if unused.
|
||||
/// </summary>
|
||||
public string FileExtension
|
||||
{
|
||||
get => _fileExtension;
|
||||
set
|
||||
{
|
||||
if (_fileExtension != value)
|
||||
{
|
||||
_fileExtension = value;
|
||||
|
||||
// Auto deselect if the current value is invalid
|
||||
if (_selectedItem != null && !IsValid(_selectedItem))
|
||||
SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public AssetPickerValidator Validator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when selected item gets changed.
|
||||
@@ -216,38 +49,6 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public bool CanEdit = true;
|
||||
|
||||
private bool IsValid(ContentItem item)
|
||||
{
|
||||
if (_fileExtension != null && !item.Path.EndsWith(_fileExtension))
|
||||
return false;
|
||||
if (CheckValid != null && !CheckValid(item))
|
||||
return false;
|
||||
if (_type == ScriptType.Null)
|
||||
return true;
|
||||
|
||||
if (item is AssetItem assetItem)
|
||||
{
|
||||
// Faster path for binary items (in-built)
|
||||
if (assetItem is BinaryAssetItem binaryItem)
|
||||
return _type.IsAssignableFrom(new ScriptType(binaryItem.Type));
|
||||
|
||||
// Type filter
|
||||
var type = TypeUtils.GetType(assetItem.TypeName);
|
||||
if (_type.IsAssignableFrom(type))
|
||||
return true;
|
||||
|
||||
// Json assets can contain any type of the object defined by the C# type (data oriented design)
|
||||
if (assetItem is JsonAssetItem && (_type.Type == typeof(JsonAsset) || _type.Type == typeof(Asset)))
|
||||
return true;
|
||||
|
||||
// Special case for scene asset references
|
||||
if (_type.Type == typeof(SceneReference) && assetItem is SceneItem)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetPicker"/> class.
|
||||
/// </summary>
|
||||
@@ -264,7 +65,8 @@ namespace FlaxEditor.GUI
|
||||
public AssetPicker(ScriptType assetType, Float2 location)
|
||||
: base(location, new Float2(DefaultIconSize + ButtonsOffset + ButtonsSize, DefaultIconSize))
|
||||
{
|
||||
_type = assetType;
|
||||
Validator = new AssetPickerValidator(assetType);
|
||||
Validator.SelectedItemChanged += OnSelectedItemChanged;
|
||||
_mousePos = Float2.Minimum;
|
||||
}
|
||||
|
||||
@@ -275,10 +77,10 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
// Update tooltip
|
||||
string tooltip;
|
||||
if (_selectedItem is AssetItem assetItem)
|
||||
if (Validator.SelectedItem is AssetItem assetItem)
|
||||
tooltip = assetItem.NamePath;
|
||||
else
|
||||
tooltip = SelectedPath;
|
||||
tooltip = Validator.SelectedPath;
|
||||
TooltipText = tooltip;
|
||||
|
||||
SelectedItemChanged?.Invoke();
|
||||
@@ -289,37 +91,13 @@ namespace FlaxEditor.GUI
|
||||
// Do the drag drop operation if has selected element
|
||||
if (new Rectangle(Float2.Zero, Size).Contains(ref _mouseDownPos))
|
||||
{
|
||||
if (_selected != null)
|
||||
DoDragDrop(DragAssets.GetDragData(_selected));
|
||||
else if (_selectedItem != null)
|
||||
DoDragDrop(DragItems.GetDragData(_selectedItem));
|
||||
if (Validator.SelectedAsset != null)
|
||||
DoDragDrop(DragAssets.GetDragData(Validator.SelectedAsset));
|
||||
else if (Validator.SelectedItem != null)
|
||||
DoDragDrop(DragItems.GetDragData(Validator.SelectedItem));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDeleted(ContentItem item)
|
||||
{
|
||||
// Deselect item
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemRenamed(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemReimported(ContentItem item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnItemDispose(ContentItem item)
|
||||
{
|
||||
// Deselect item
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
private Rectangle IconRect => new Rectangle(0, 0, Height, Height);
|
||||
|
||||
private Rectangle Button1Rect => new Rectangle(Height + ButtonsOffset, 0, ButtonsSize, ButtonsSize);
|
||||
@@ -341,10 +119,10 @@ namespace FlaxEditor.GUI
|
||||
if (CanEdit)
|
||||
Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
if (_selectedItem != null)
|
||||
if (Validator.SelectedItem != null)
|
||||
{
|
||||
// Draw item preview
|
||||
_selectedItem.DrawThumbnail(ref iconRect);
|
||||
Validator.SelectedItem.DrawThumbnail(ref iconRect);
|
||||
|
||||
// Draw buttons
|
||||
if (CanEdit)
|
||||
@@ -363,7 +141,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
_selectedItem.ShortName,
|
||||
Validator.SelectedItem.ShortName,
|
||||
new Rectangle(button1Rect.Right + 2, 0, sizeForTextLeft, ButtonsSize),
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
@@ -371,7 +149,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
// Check if has no item but has an asset (eg. virtual asset)
|
||||
else if (_selected)
|
||||
else if (Validator.SelectedAsset)
|
||||
{
|
||||
// Draw remove button
|
||||
Render2D.DrawSprite(style.Cross, button3Rect, button3Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
|
||||
@@ -380,8 +158,8 @@ namespace FlaxEditor.GUI
|
||||
float sizeForTextLeft = Width - button1Rect.Right;
|
||||
if (sizeForTextLeft > 30)
|
||||
{
|
||||
var name = _selected.GetType().Name;
|
||||
if (_selected.IsVirtual)
|
||||
var name = Validator.SelectedAsset.GetType().Name;
|
||||
if (Validator.SelectedAsset.IsVirtual)
|
||||
name += " (virtual)";
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
@@ -395,8 +173,8 @@ namespace FlaxEditor.GUI
|
||||
else
|
||||
{
|
||||
// No element selected
|
||||
Render2D.FillRectangle(iconRect, new Color(0.2f));
|
||||
Render2D.DrawText(style.FontMedium, "No asset\nselected", iconRect, Color.Wheat, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
|
||||
Render2D.DrawText(style.FontMedium, "No asset\nselected", iconRect, Color.Orange, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||
}
|
||||
|
||||
// Check if drag is over
|
||||
@@ -407,9 +185,7 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
_selectedItem?.RemoveReference(this);
|
||||
_selectedItem = null;
|
||||
_selected = null;
|
||||
Validator.OnDestroy();
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
@@ -463,57 +239,57 @@ namespace FlaxEditor.GUI
|
||||
// Buttons logic
|
||||
if (!CanEdit)
|
||||
{
|
||||
if (Button1Rect.Contains(location) && _selectedItem != null)
|
||||
if (Button1Rect.Contains(location) && Validator.SelectedItem != null)
|
||||
{
|
||||
// Select asset
|
||||
Editor.Instance.Windows.ContentWin.Select(_selectedItem);
|
||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||
}
|
||||
}
|
||||
else if (Button1Rect.Contains(location))
|
||||
{
|
||||
Focus();
|
||||
if (_type != ScriptType.Null)
|
||||
if (Validator.AssetType != ScriptType.Null)
|
||||
{
|
||||
// Show asset picker popup
|
||||
var popup = AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
var popup = AssetSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
||||
{
|
||||
SelectedItem = item;
|
||||
Validator.SelectedItem = item;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
if (_selected != null)
|
||||
if (Validator.SelectedAsset != null)
|
||||
{
|
||||
var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path);
|
||||
var selectedAssetName = Path.GetFileNameWithoutExtension(Validator.SelectedAsset.Path);
|
||||
popup.ScrollToAndHighlightItemByName(selectedAssetName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show content item picker popup
|
||||
var popup = ContentSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, item =>
|
||||
var popup = ContentSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
||||
{
|
||||
SelectedItem = item;
|
||||
Validator.SelectedItem = item;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
if (_selectedItem != null)
|
||||
if (Validator.SelectedItem != null)
|
||||
{
|
||||
popup.ScrollToAndHighlightItemByName(_selectedItem.ShortName);
|
||||
popup.ScrollToAndHighlightItemByName(Validator.SelectedItem.ShortName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_selected != null || _selectedItem != null)
|
||||
else if (Validator.SelectedAsset != null || Validator.SelectedItem != null)
|
||||
{
|
||||
if (Button2Rect.Contains(location) && _selectedItem != null)
|
||||
if (Button2Rect.Contains(location) && Validator.SelectedItem != null)
|
||||
{
|
||||
// Select asset
|
||||
Editor.Instance.Windows.ContentWin.Select(_selectedItem);
|
||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||
}
|
||||
else if (Button3Rect.Contains(location))
|
||||
{
|
||||
// Deselect asset
|
||||
Focus();
|
||||
SelectedItem = null;
|
||||
Validator.SelectedItem = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -540,10 +316,10 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
Focus();
|
||||
|
||||
if (_selectedItem != null && IconRect.Contains(location))
|
||||
if (Validator.SelectedItem != null && IconRect.Contains(location))
|
||||
{
|
||||
// Open it
|
||||
Editor.Instance.ContentEditing.Open(_selectedItem);
|
||||
Editor.Instance.ContentEditing.Open(Validator.SelectedItem);
|
||||
}
|
||||
|
||||
// Handled
|
||||
@@ -557,7 +333,7 @@ namespace FlaxEditor.GUI
|
||||
|
||||
// Check if drop asset
|
||||
if (_dragOverElement == null)
|
||||
_dragOverElement = new DragItems(IsValid);
|
||||
_dragOverElement = new DragItems(Validator.IsValid);
|
||||
if (CanEdit && _dragOverElement.OnDragEnter(data))
|
||||
{
|
||||
}
|
||||
@@ -590,7 +366,7 @@ namespace FlaxEditor.GUI
|
||||
if (CanEdit && _dragOverElement.HasValidDrag)
|
||||
{
|
||||
// Select element
|
||||
SelectedItem = _dragOverElement.Objects[0];
|
||||
Validator.SelectedItem = _dragOverElement.Objects[0];
|
||||
}
|
||||
|
||||
// Clear cache
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
/// </summary>
|
||||
public DialogResult Result => _result;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the dialog.
|
||||
/// </summary>
|
||||
public Float2 DialogSize => _dialogSize;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Dialog"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -465,36 +465,47 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
if (Parent.Parent is SplitPanel splitter)
|
||||
{
|
||||
// Check if has any child panels
|
||||
var childPanel = new List<DockPanel>(_childPanels);
|
||||
for (int i = 0; i < childPanel.Count; i++)
|
||||
// Check if there is another nested dock panel inside this dock panel and extract it here
|
||||
var childPanels = _childPanels.ToArray();
|
||||
if (childPanels.Length != 0)
|
||||
{
|
||||
// Undock all tabs
|
||||
var panel = childPanel[i];
|
||||
int count = panel.TabsCount;
|
||||
while (count-- > 0)
|
||||
// Move tabs from child panels into this one
|
||||
DockWindow selectedTab = null;
|
||||
foreach (var childPanel in childPanels)
|
||||
{
|
||||
panel.GetTab(0).Close();
|
||||
var childPanelTabs = childPanel.Tabs.ToArray();
|
||||
for (var i = 0; i < childPanelTabs.Length; i++)
|
||||
{
|
||||
var childPanelTab = childPanelTabs[i];
|
||||
if (selectedTab == null && childPanelTab.IsSelected)
|
||||
selectedTab = childPanelTab;
|
||||
childPanel.UndockWindow(childPanelTab);
|
||||
AddTab(childPanelTab, false);
|
||||
}
|
||||
}
|
||||
if (selectedTab != null)
|
||||
SelectTab(selectedTab);
|
||||
}
|
||||
|
||||
// Unlink splitter
|
||||
var splitterParent = splitter.Parent;
|
||||
Assert.IsNotNull(splitterParent);
|
||||
splitter.Parent = null;
|
||||
|
||||
// Move controls from second split panel to the split panel parent
|
||||
var scrPanel = Parent == splitter.Panel2 ? splitter.Panel1 : splitter.Panel2;
|
||||
var srcPanelChildrenCount = scrPanel.ChildrenCount;
|
||||
for (int i = srcPanelChildrenCount - 1; i >= 0 && scrPanel.ChildrenCount > 0; i--)
|
||||
else
|
||||
{
|
||||
scrPanel.GetChild(i).Parent = splitterParent;
|
||||
}
|
||||
Assert.IsTrue(scrPanel.ChildrenCount == 0);
|
||||
Assert.IsTrue(splitterParent.ChildrenCount == srcPanelChildrenCount);
|
||||
// Unlink splitter
|
||||
var splitterParent = splitter.Parent;
|
||||
Assert.IsNotNull(splitterParent);
|
||||
splitter.Parent = null;
|
||||
|
||||
// Delete
|
||||
splitter.Dispose();
|
||||
// Move controls from second split panel to the split panel parent
|
||||
var scrPanel = Parent == splitter.Panel2 ? splitter.Panel1 : splitter.Panel2;
|
||||
var srcPanelChildrenCount = scrPanel.ChildrenCount;
|
||||
for (int i = srcPanelChildrenCount - 1; i >= 0 && scrPanel.ChildrenCount > 0; i--)
|
||||
{
|
||||
scrPanel.GetChild(i).Parent = splitterParent;
|
||||
}
|
||||
Assert.IsTrue(scrPanel.ChildrenCount == 0);
|
||||
Assert.IsTrue(splitterParent.ChildrenCount == srcPanelChildrenCount);
|
||||
|
||||
// Delete
|
||||
splitter.Dispose();
|
||||
}
|
||||
}
|
||||
else if (!IsMaster)
|
||||
{
|
||||
@@ -582,19 +593,17 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// Adds the tab.
|
||||
/// </summary>
|
||||
/// <param name="window">The window to insert as a tab.</param>
|
||||
protected virtual void AddTab(DockWindow window)
|
||||
/// <param name="autoSelect">True if auto-select newly added tab.</param>
|
||||
protected virtual void AddTab(DockWindow window, bool autoSelect = true)
|
||||
{
|
||||
// Dock
|
||||
_tabs.Add(window);
|
||||
window.ParentDockPanel = this;
|
||||
|
||||
// Select tab
|
||||
SelectTab(window);
|
||||
if (autoSelect)
|
||||
SelectTab(window);
|
||||
}
|
||||
|
||||
private void CreateTabsProxy()
|
||||
{
|
||||
// Check if has no tabs proxy created
|
||||
if (_tabsProxy == null)
|
||||
{
|
||||
// Create proxy and make set simple full dock
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
public class DockPanelProxy : ContainerControl
|
||||
{
|
||||
private DockPanel _panel;
|
||||
private double _dragEnterTime = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The is mouse down flag (left button).
|
||||
@@ -256,8 +257,8 @@ namespace FlaxEditor.GUI.Docking
|
||||
else
|
||||
{
|
||||
tabColor = style.BackgroundHighlighted;
|
||||
Render2D.DrawLine(tabRect.BottomLeft - new Float2(0 , 1), tabRect.UpperLeft, tabColor);
|
||||
Render2D.DrawLine(tabRect.BottomRight - new Float2(0 , 1), tabRect.UpperRight, tabColor);
|
||||
Render2D.DrawLine(tabRect.BottomLeft - new Float2(0, 1), tabRect.UpperLeft, tabColor);
|
||||
Render2D.DrawLine(tabRect.BottomRight - new Float2(0, 1), tabRect.UpperRight, tabColor);
|
||||
}
|
||||
|
||||
if (tab.Icon.IsValid)
|
||||
@@ -477,11 +478,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
var result = base.OnDragEnter(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
if (TrySelectTabUnderLocation(ref location))
|
||||
return DragDropEffect.Move;
|
||||
|
||||
return DragDropEffect.None;
|
||||
return TrySelectTabUnderLocation(ref location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -490,11 +487,15 @@ namespace FlaxEditor.GUI.Docking
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
return TrySelectTabUnderLocation(ref location);
|
||||
}
|
||||
|
||||
if (TrySelectTabUnderLocation(ref location))
|
||||
return DragDropEffect.Move;
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragEnterTime = -1;
|
||||
|
||||
return DragDropEffect.None;
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -503,17 +504,25 @@ namespace FlaxEditor.GUI.Docking
|
||||
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
|
||||
}
|
||||
|
||||
private bool TrySelectTabUnderLocation(ref Float2 location)
|
||||
private DragDropEffect TrySelectTabUnderLocation(ref Float2 location)
|
||||
{
|
||||
var tab = GetTabAtPos(location, out _);
|
||||
if (tab != null)
|
||||
{
|
||||
// Auto-select tab only if drag takes some time
|
||||
var time = Platform.TimeSeconds;
|
||||
if (_dragEnterTime < 0)
|
||||
_dragEnterTime = time;
|
||||
if (time - _dragEnterTime < 0.3f)
|
||||
return DragDropEffect.Link;
|
||||
_dragEnterTime = -1;
|
||||
|
||||
_panel.SelectTab(tab);
|
||||
Update(0); // Fake update
|
||||
return true;
|
||||
return DragDropEffect.Move;
|
||||
}
|
||||
|
||||
return false;
|
||||
_dragEnterTime = -1;
|
||||
return DragDropEffect.None;
|
||||
}
|
||||
|
||||
private void ShowContextMenu(DockWindow tab, ref Float2 location)
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.Size = size;
|
||||
settings.Position = location;
|
||||
settings.MinimumSize = new Float2(1);
|
||||
settings.MaximumSize = new Float2(4096);
|
||||
settings.MaximumSize = Float2.Zero; // Unlimited size
|
||||
settings.Fullscreen = false;
|
||||
settings.HasBorder = true;
|
||||
settings.SupportsTransparency = false;
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace FlaxEditor.GUI.Input
|
||||
[HideInEditor]
|
||||
public class ColorValueBox : Control
|
||||
{
|
||||
private bool _isMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate function used for the color picker events handling.
|
||||
/// </summary>
|
||||
@@ -134,11 +136,22 @@ namespace FlaxEditor.GUI.Input
|
||||
Render2D.DrawRectangle(r, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
_isMouseDown = true;
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
Focus();
|
||||
OnSubmit();
|
||||
if (_isMouseDown)
|
||||
{
|
||||
_isMouseDown = false;
|
||||
Focus();
|
||||
OnSubmit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,9 +100,10 @@ namespace FlaxEditor.GUI
|
||||
AutoResize = true;
|
||||
Offsets = new Margin(0, 0, 0, IconSize);
|
||||
|
||||
_mouseOverColor = style.Foreground;
|
||||
_selectedColor = style.Foreground;
|
||||
_defaultColor = style.ForegroundGrey;
|
||||
// Ignoring style on purpose (style would make sense if the icons were white, but they are colored)
|
||||
_mouseOverColor = new Color(0.8f, 0.8f, 0.8f, 1f);
|
||||
_selectedColor = Color.White;
|
||||
_defaultColor = new Color(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
|
||||
for (int i = 0; i < platforms.Length; i++)
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace FlaxEditor.GUI
|
||||
rect.Width -= leftDepthMargin;
|
||||
|
||||
Render2D.PushClip(rect);
|
||||
Render2D.DrawText(style.FontMedium, text, rect, Color.White, column.CellAlignment, TextAlignment.Center);
|
||||
Render2D.DrawText(style.FontMedium, text, rect, style.Foreground, column.CellAlignment, TextAlignment.Center);
|
||||
Render2D.PopClip();
|
||||
|
||||
x += width;
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace FlaxEditor.GUI.Tabs
|
||||
[HideInEditor]
|
||||
public class Tab : ContainerControl
|
||||
{
|
||||
internal Tabs _selectedInTabs;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text.
|
||||
/// </summary>
|
||||
@@ -86,5 +88,25 @@ namespace FlaxEditor.GUI.Tabs
|
||||
{
|
||||
return new Tabs.TabHeader((Tabs)Parent, this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnParentChangedInternal()
|
||||
{
|
||||
if (_selectedInTabs != null)
|
||||
_selectedInTabs.SelectedTab = null;
|
||||
|
||||
base.OnParentChangedInternal();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
if (_selectedInTabs != null)
|
||||
_selectedInTabs.SelectedTab = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ namespace FlaxEditor.GUI.Tabs
|
||||
/// </summary>
|
||||
public Tab SelectedTab
|
||||
{
|
||||
get => _selectedIndex == -1 && Children.Count > _selectedIndex + 1 ? null : Children[_selectedIndex + 1] as Tab;
|
||||
get => _selectedIndex < 0 || Children.Count <= _selectedIndex ? null : Children[_selectedIndex + 1] as Tab;
|
||||
set => SelectedTabIndex = value != null ? Children.IndexOf(value) - 1 : -1;
|
||||
}
|
||||
|
||||
@@ -263,7 +263,12 @@ namespace FlaxEditor.GUI.Tabs
|
||||
// Check if index will change
|
||||
if (_selectedIndex != index)
|
||||
{
|
||||
SelectedTab?.OnDeselected();
|
||||
var prev = SelectedTab;
|
||||
if (prev != null)
|
||||
{
|
||||
prev._selectedInTabs = null;
|
||||
prev.OnDeselected();
|
||||
}
|
||||
_selectedIndex = index;
|
||||
PerformLayout();
|
||||
OnSelectedTabChanged();
|
||||
@@ -342,8 +347,13 @@ namespace FlaxEditor.GUI.Tabs
|
||||
/// </summary>
|
||||
protected virtual void OnSelectedTabChanged()
|
||||
{
|
||||
var selectedTab = SelectedTab;
|
||||
SelectedTabChanged?.Invoke(this);
|
||||
SelectedTab?.OnSelected();
|
||||
if (selectedTab != null)
|
||||
{
|
||||
selectedTab._selectedInTabs = this;
|
||||
selectedTab.OnSelected();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -627,10 +627,11 @@ namespace FlaxEditor.GUI.Timeline
|
||||
Parent = this
|
||||
};
|
||||
|
||||
var style = Style.Current;
|
||||
var headerTopArea = new ContainerControl
|
||||
{
|
||||
AutoFocus = false,
|
||||
BackgroundColor = Style.Current.LightBackground,
|
||||
BackgroundColor = style.LightBackground,
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||
Offsets = new Margin(0, 0, 0, HeaderTopAreaHeight),
|
||||
Parent = _splitter.Panel1
|
||||
@@ -683,7 +684,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
{
|
||||
AutoFocus = false,
|
||||
ClipChildren = false,
|
||||
BackgroundColor = Style.Current.LightBackground,
|
||||
BackgroundColor = style.LightBackground,
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchBottom,
|
||||
Offsets = new Margin(0, 0, -playbackButtonsSize, playbackButtonsSize),
|
||||
Parent = _splitter.Panel1
|
||||
@@ -845,7 +846,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
_timeIntervalsHeader = new TimeIntervalsHeader(this)
|
||||
{
|
||||
AutoFocus = false,
|
||||
BackgroundColor = Style.Current.Background.RGBMultiplied(0.9f),
|
||||
BackgroundColor = style.Background.RGBMultiplied(0.9f),
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||
Offsets = new Margin(0, 0, 0, HeaderTopAreaHeight),
|
||||
Parent = _splitter.Panel2
|
||||
@@ -854,7 +855,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
{
|
||||
AutoFocus = false,
|
||||
ClipChildren = false,
|
||||
BackgroundColor = Style.Current.Background.RGBMultiplied(0.7f),
|
||||
BackgroundColor = style.Background.RGBMultiplied(0.7f),
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = new Margin(0, 0, HeaderTopAreaHeight, 0),
|
||||
Parent = _splitter.Panel2
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
if (AssetID == value?.ID)
|
||||
return;
|
||||
AssetID = value?.ID ?? Guid.Empty;
|
||||
_picker.SelectedAsset = value;
|
||||
_picker.Validator.SelectedAsset = value;
|
||||
OnAssetChanged();
|
||||
Timeline?.MarkAsEdited();
|
||||
}
|
||||
@@ -63,10 +63,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
|
||||
private void OnPickerSelectedItemChanged()
|
||||
{
|
||||
if (Asset == (TAsset)_picker.SelectedAsset)
|
||||
if (Asset == (TAsset)_picker.Validator.SelectedAsset)
|
||||
return;
|
||||
using (new TrackUndoBlock(this))
|
||||
Asset = (TAsset)_picker.SelectedAsset;
|
||||
Asset = (TAsset)_picker.Validator.SelectedAsset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -106,5 +106,11 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
/// <param name="nodes">The nodes to select</param>
|
||||
void Select(List<SceneGraph.SceneGraphNode> nodes);
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the actor in the viewport hierarchy.
|
||||
/// </summary>
|
||||
/// <param name="actor">The new actor to spawn.</param>
|
||||
void Spawn(Actor actor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,8 @@ namespace FlaxEditor.Gizmo
|
||||
if (isSelected)
|
||||
{
|
||||
GetSelectedObjectsBounds(out var selectionBounds, out _);
|
||||
ray.Position = ray.GetPoint(selectionBounds.Size.Y * 0.5f);
|
||||
var offset = Mathf.Max(selectionBounds.Size.Y * 0.5f, 1.0f);
|
||||
ray.Position = ray.GetPoint(offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -330,14 +330,15 @@ bool ManagedEditor::CanReloadScripts()
|
||||
|
||||
bool ManagedEditor::CanAutoBuildCSG()
|
||||
{
|
||||
if (!ManagedEditorOptions.AutoRebuildCSG)
|
||||
return false;
|
||||
|
||||
// Skip calls from non-managed thread (eg. physics worker)
|
||||
if (!MCore::Thread::IsAttached())
|
||||
return false;
|
||||
|
||||
if (!HasManagedInstance())
|
||||
return false;
|
||||
if (!ManagedEditorOptions.AutoRebuildCSG)
|
||||
return false;
|
||||
if (Internal_CanAutoBuildCSG == nullptr)
|
||||
{
|
||||
Internal_CanAutoBuildCSG = GetClass()->GetMethod("Internal_CanAutoBuildCSG");
|
||||
@@ -348,14 +349,15 @@ bool ManagedEditor::CanAutoBuildCSG()
|
||||
|
||||
bool ManagedEditor::CanAutoBuildNavMesh()
|
||||
{
|
||||
if (!ManagedEditorOptions.AutoRebuildNavMesh)
|
||||
return false;
|
||||
|
||||
// Skip calls from non-managed thread (eg. physics worker)
|
||||
if (!MCore::Thread::IsAttached())
|
||||
return false;
|
||||
|
||||
if (!HasManagedInstance())
|
||||
return false;
|
||||
if (!ManagedEditorOptions.AutoRebuildNavMesh)
|
||||
return false;
|
||||
if (Internal_CanAutoBuildNavMesh == nullptr)
|
||||
{
|
||||
Internal_CanAutoBuildNavMesh = GetClass()->GetMethod("Internal_CanAutoBuildNavMesh");
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace FlaxEditor.Modules
|
||||
if (!Editor.StateMachine.CurrentState.CanEditScene)
|
||||
return;
|
||||
undo = Editor.Undo;
|
||||
Editor.Scene.MarkSceneEdited(actor.Scene);
|
||||
}
|
||||
|
||||
// Record undo for prefab creating (backend links the target instance with the prefab)
|
||||
|
||||
@@ -242,7 +242,6 @@ namespace FlaxEditor.Modules
|
||||
/// <param name="additive">True if don't close opened scenes and just add new scene to them, otherwise will release current scenes and load single one.</param>
|
||||
public void OpenScene(Guid sceneId, bool additive = false)
|
||||
{
|
||||
// Check if cannot change scene now
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
@@ -266,13 +265,35 @@ namespace FlaxEditor.Modules
|
||||
Editor.StateMachine.ChangingScenesState.LoadScene(sceneId, additive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reload all loaded scenes.
|
||||
/// </summary>
|
||||
public void ReloadScenes()
|
||||
{
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
if (!Editor.IsPlayMode)
|
||||
{
|
||||
if (CheckSaveBeforeClose())
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload scenes
|
||||
foreach (var scene in Level.Scenes)
|
||||
{
|
||||
var sceneId = scene.ID;
|
||||
Level.UnloadScene(scene);
|
||||
Level.LoadScene(sceneId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes scene (async).
|
||||
/// </summary>
|
||||
/// <param name="scene">The scene.</param>
|
||||
public void CloseScene(Scene scene)
|
||||
{
|
||||
// Check if cannot change scene now
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
@@ -296,7 +317,6 @@ namespace FlaxEditor.Modules
|
||||
/// </summary>
|
||||
public void CloseAllScenes()
|
||||
{
|
||||
// Check if cannot change scene now
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
@@ -321,7 +341,6 @@ namespace FlaxEditor.Modules
|
||||
/// <param name="scene">The scene to not close.</param>
|
||||
public void CloseAllScenesExcept(Scene scene)
|
||||
{
|
||||
// Check if cannot change scene now
|
||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||
return;
|
||||
|
||||
|
||||
@@ -147,6 +147,17 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
}
|
||||
if (key != null)
|
||||
xml.TryGetValue(key, out text);
|
||||
|
||||
// Customize tooltips for properties to be more human-readable in UI
|
||||
if (text != null && memberType.HasFlag(MemberTypes.Property) && text.StartsWith("Gets or sets ", StringComparison.Ordinal))
|
||||
{
|
||||
text = text.Substring(13);
|
||||
unsafe
|
||||
{
|
||||
fixed (char* e = text)
|
||||
e[0] = char.ToUpper(e[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace FlaxEditor.Modules
|
||||
ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>();
|
||||
|
||||
private ContextMenuButton _menuFileSaveScenes;
|
||||
private ContextMenuButton _menuFileReloadScenes;
|
||||
private ContextMenuButton _menuFileCloseScenes;
|
||||
private ContextMenuButton _menuFileOpenScriptsProject;
|
||||
private ContextMenuButton _menuFileGenerateScriptsProjectFiles;
|
||||
@@ -470,13 +471,13 @@ namespace FlaxEditor.Modules
|
||||
// Place dialog nearby the target control
|
||||
var targetControlDesktopCenter = targetControl.PointToScreen(targetControl.Size * 0.5f);
|
||||
var desktopSize = Platform.GetMonitorBounds(targetControlDesktopCenter);
|
||||
var pos = targetControlDesktopCenter + new Float2(10.0f, -dialog.Height * 0.5f);
|
||||
var dialogEnd = pos + dialog.Size;
|
||||
var pos = targetControlDesktopCenter + new Float2(10.0f, -dialog.DialogSize.Y * 0.5f);
|
||||
var dialogEnd = pos + dialog.DialogSize;
|
||||
var desktopEnd = desktopSize.BottomRight - new Float2(10.0f);
|
||||
if (dialogEnd.X >= desktopEnd.X || dialogEnd.Y >= desktopEnd.Y)
|
||||
pos = targetControl.PointToScreen(Float2.Zero) - new Float2(10.0f + dialog.Width, dialog.Height);
|
||||
pos = targetControl.PointToScreen(Float2.Zero) - new Float2(10.0f + dialog.DialogSize.X, dialog.DialogSize.Y);
|
||||
var desktopBounds = Platform.VirtualDesktopBounds;
|
||||
pos = Float2.Clamp(pos, desktopBounds.UpperLeft, desktopBounds.BottomRight - dialog.Size);
|
||||
pos = Float2.Clamp(pos, desktopBounds.UpperLeft, desktopBounds.BottomRight - dialog.DialogSize);
|
||||
dialog.RootWindow.Window.Position = pos;
|
||||
|
||||
// Register for context menu (prevent auto-closing context menu when selecting color)
|
||||
@@ -527,6 +528,7 @@ namespace FlaxEditor.Modules
|
||||
_menuFileSaveAll = cm.AddButton("Save All", inputOptions.Save, Editor.SaveAll);
|
||||
_menuFileSaveScenes = cm.AddButton("Save scenes", inputOptions.SaveScenes, Editor.Scene.SaveScenes);
|
||||
_menuFileCloseScenes = cm.AddButton("Close scenes", inputOptions.CloseScenes, Editor.Scene.CloseAllScenes);
|
||||
_menuFileReloadScenes = cm.AddButton("Reload scenes", Editor.Scene.ReloadScenes);
|
||||
cm.AddSeparator();
|
||||
_menuFileOpenScriptsProject = cm.AddButton("Open scripts project", inputOptions.OpenScriptsProject, Editor.CodeEditing.OpenSolution);
|
||||
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
|
||||
@@ -830,6 +832,7 @@ namespace FlaxEditor.Modules
|
||||
|
||||
_menuFileSaveScenes.Enabled = hasOpenedScene;
|
||||
_menuFileCloseScenes.Enabled = hasOpenedScene;
|
||||
_menuFileReloadScenes.Enabled = hasOpenedScene;
|
||||
_menuFileGenerateScriptsProjectFiles.Enabled = !Editor.ProgressReporting.GenerateScriptsProjectFiles.IsActive;
|
||||
|
||||
c.PerformLayout();
|
||||
|
||||
@@ -171,9 +171,13 @@ namespace FlaxEditor.Modules
|
||||
var mainWindow = MainWindow;
|
||||
if (mainWindow)
|
||||
{
|
||||
var projectPath = Globals.ProjectFolder.Replace('/', '\\');
|
||||
var platformBit = Platform.Is64BitApp ? "64" : "32";
|
||||
var title = string.Format("Flax Editor - \'{0}\' ({1}-bit)", projectPath, platformBit);
|
||||
var projectPath = Globals.ProjectFolder;
|
||||
#if PLATFORM_WINDOWS
|
||||
projectPath = projectPath.Replace('/', '\\');
|
||||
#endif
|
||||
var engineVersion = Editor.EngineProject.Version;
|
||||
var engineVersionText = engineVersion.Revision > 0 ? $"{engineVersion.Major}.{engineVersion.Minor}.{engineVersion.Revision}" : $"{engineVersion.Major}.{engineVersion.Minor}";
|
||||
var title = $"Flax Editor {engineVersionText} - \'{projectPath}\'";
|
||||
mainWindow.Title = title;
|
||||
}
|
||||
}
|
||||
@@ -735,7 +739,6 @@ namespace FlaxEditor.Modules
|
||||
settings.Size = Platform.DesktopSize * 0.75f;
|
||||
settings.StartPosition = WindowStartPosition.CenterScreen;
|
||||
settings.ShowAfterFirstPaint = true;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
if (!Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
|
||||
{
|
||||
@@ -747,12 +750,9 @@ namespace FlaxEditor.Modules
|
||||
#elif PLATFORM_LINUX
|
||||
settings.HasBorder = false;
|
||||
#endif
|
||||
|
||||
MainWindow = Platform.CreateWindow(ref settings);
|
||||
|
||||
if (MainWindow == null)
|
||||
{
|
||||
// Error
|
||||
Editor.LogError("Failed to create editor main window!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Common"), EditorOrder(230)]
|
||||
public InputBinding RotateSelection = new InputBinding(KeyboardKeys.R);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "F11")]
|
||||
[EditorDisplay("Common"), EditorOrder(240)]
|
||||
public InputBinding ToggleFullscreen = new InputBinding(KeyboardKeys.F11);
|
||||
|
||||
#endregion
|
||||
|
||||
#region File
|
||||
@@ -208,16 +212,20 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Debugger", "Continue"), EditorOrder(810)]
|
||||
public InputBinding DebuggerContinue = new InputBinding(KeyboardKeys.F5);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+F11")]
|
||||
[EditorDisplay("Debugger", "Unlock mouse in Play Mode"), EditorOrder(820)]
|
||||
public InputBinding DebuggerUnlockMouse = new InputBinding(KeyboardKeys.F11, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "F10")]
|
||||
[EditorDisplay("Debugger", "Step Over"), EditorOrder(820)]
|
||||
[EditorDisplay("Debugger", "Step Over"), EditorOrder(830)]
|
||||
public InputBinding DebuggerStepOver = new InputBinding(KeyboardKeys.F10);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "F11")]
|
||||
[EditorDisplay("Debugger", "Step Into"), EditorOrder(830)]
|
||||
[EditorDisplay("Debugger", "Step Into"), EditorOrder(840)]
|
||||
public InputBinding DebuggerStepInto = new InputBinding(KeyboardKeys.F11);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+F11")]
|
||||
[EditorDisplay("Debugger", "Step Out"), EditorOrder(840)]
|
||||
[EditorDisplay("Debugger", "Step Out"), EditorOrder(850)]
|
||||
public InputBinding DebuggerStepOut = new InputBinding(KeyboardKeys.F11, KeyboardKeys.Shift);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -208,13 +208,20 @@ namespace FlaxEditor.Options
|
||||
|
||||
// If a non-default style was chosen, switch to that style
|
||||
string styleName = themeOptions.SelectedStyle;
|
||||
if (styleName != "Default" && themeOptions.Styles.TryGetValue(styleName, out var style) && style != null)
|
||||
if (styleName != ThemeOptions.DefaultName && styleName != ThemeOptions.LightDefault && themeOptions.Styles.TryGetValue(styleName, out var style) && style != null)
|
||||
{
|
||||
Style.Current = style;
|
||||
}
|
||||
else
|
||||
{
|
||||
Style.Current = CreateDefaultStyle();
|
||||
if (styleName == ThemeOptions.LightDefault)
|
||||
{
|
||||
Style.Current = CreateLightStyle();
|
||||
}
|
||||
else
|
||||
{
|
||||
Style.Current = CreateDefaultStyle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +231,6 @@ namespace FlaxEditor.Options
|
||||
/// <returns>The style object.</returns>
|
||||
public Style CreateDefaultStyle()
|
||||
{
|
||||
// Metro Style colors
|
||||
var options = Options;
|
||||
var style = new Style
|
||||
{
|
||||
@@ -233,6 +239,7 @@ namespace FlaxEditor.Options
|
||||
Foreground = Color.FromBgra(0xFFFFFFFF),
|
||||
ForegroundGrey = Color.FromBgra(0xFFA9A9B3),
|
||||
ForegroundDisabled = Color.FromBgra(0xFF787883),
|
||||
ForegroundViewport = Color.FromBgra(0xFFFFFFFF),
|
||||
BackgroundHighlighted = Color.FromBgra(0xFF54545C),
|
||||
BorderHighlighted = Color.FromBgra(0xFF6A6A75),
|
||||
BackgroundSelected = Color.FromBgra(0xFF007ACC),
|
||||
@@ -274,7 +281,58 @@ namespace FlaxEditor.Options
|
||||
SharedTooltip = new Tooltip(),
|
||||
};
|
||||
style.DragWindow = style.BackgroundSelected * 0.7f;
|
||||
return style;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the light style (2nd default).
|
||||
/// </summary>
|
||||
/// <returns>The style object.</returns>
|
||||
public Style CreateLightStyle()
|
||||
{
|
||||
var options = Options;
|
||||
var style = new Style
|
||||
{
|
||||
Background = new Color(0.92f, 0.92f, 0.92f, 1f),
|
||||
LightBackground = new Color(0.84f, 0.84f, 0.88f, 1f),
|
||||
DragWindow = new Color(0.0f, 0.26f, 0.43f, 0.70f),
|
||||
Foreground = new Color(0.0f, 0.0f, 0.0f, 1f),
|
||||
ForegroundGrey = new Color(0.30f, 0.30f, 0.31f, 1f),
|
||||
ForegroundDisabled = new Color(0.45f, 0.45f, 0.49f, 1f),
|
||||
ForegroundViewport = new Color(1.0f, 1.0f, 1.0f, 1f),
|
||||
BackgroundHighlighted = new Color(0.59f, 0.59f, 0.64f, 1f),
|
||||
BorderHighlighted = new Color(0.50f, 0.50f, 0.55f, 1f),
|
||||
BackgroundSelected = new Color(0.00f, 0.46f, 0.78f, 0.78f),
|
||||
BorderSelected = new Color(0.11f, 0.57f, 0.88f, 0.65f),
|
||||
BackgroundNormal = new Color(0.67f, 0.67f, 0.75f, 1f),
|
||||
BorderNormal = new Color(0.59f, 0.59f, 0.64f, 1f),
|
||||
TextBoxBackground = new Color(0.75f, 0.75f, 0.81f, 1f),
|
||||
TextBoxBackgroundSelected = new Color(0.73f, 0.73f, 0.80f, 1f),
|
||||
CollectionBackgroundColor = new Color(0.85f, 0.85f, 0.88f, 1f),
|
||||
ProgressNormal = new Color(0.03f, 0.65f, 0.12f, 1f),
|
||||
|
||||
// Fonts
|
||||
FontTitle = options.Interface.TitleFont.GetFont(),
|
||||
FontLarge = options.Interface.LargeFont.GetFont(),
|
||||
FontMedium = options.Interface.MediumFont.GetFont(),
|
||||
FontSmall = options.Interface.SmallFont.GetFont(),
|
||||
|
||||
// Icons
|
||||
ArrowDown = Editor.Icons.ArrowDown12,
|
||||
ArrowRight = Editor.Icons.ArrowRight12,
|
||||
Search = Editor.Icons.Search12,
|
||||
Settings = Editor.Icons.Settings12,
|
||||
Cross = Editor.Icons.Cross12,
|
||||
CheckBoxIntermediate = Editor.Icons.CheckBoxIntermediate12,
|
||||
CheckBoxTick = Editor.Icons.CheckBoxTick12,
|
||||
StatusBarSizeGrip = Editor.Icons.WindowDrag12,
|
||||
Translate = Editor.Icons.Translate32,
|
||||
Rotate = Editor.Icons.Rotate32,
|
||||
Scale = Editor.Icons.Scale32,
|
||||
Scalar = Editor.Icons.Scalar32,
|
||||
|
||||
SharedTooltip = new Tooltip(),
|
||||
};
|
||||
return style;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace FlaxEditor.Options
|
||||
[CustomEditor(typeof(ThemeOptionsEditor))]
|
||||
public sealed class ThemeOptions
|
||||
{
|
||||
internal const string DefaultName = "Default";
|
||||
internal const string LightDefault = "LightDefault";
|
||||
|
||||
internal class ThemeOptionsEditor : Editor<ThemeOptions>
|
||||
{
|
||||
private LabelElement _infoLabel;
|
||||
@@ -63,13 +66,14 @@ namespace FlaxEditor.Options
|
||||
private void ReloadOptions(ComboBox obj)
|
||||
{
|
||||
var themeOptions = (ThemeOptions)ParentEditor.Values[0];
|
||||
var options = new string[themeOptions.Styles.Count + 1];
|
||||
options[0] = "Default";
|
||||
var options = new string[themeOptions.Styles.Count + 2];
|
||||
options[0] = DefaultName;
|
||||
options[1] = LightDefault;
|
||||
|
||||
int i = 0;
|
||||
foreach (var styleName in themeOptions.Styles.Keys)
|
||||
{
|
||||
options[i + 1] = styleName;
|
||||
options[i + 2] = styleName;
|
||||
i++;
|
||||
}
|
||||
_combobox.ComboBox.SetItems(options);
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace FlaxEditor.Progress.Handlers
|
||||
ScriptsBuilder.ScriptsReloadCalled += () => OnUpdate(0.8f, "Reloading scripts...");
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
ScriptsBuilder.ScriptsReload += OnScriptsReload;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
@@ -38,14 +37,6 @@ namespace FlaxEditor.Progress.Handlers
|
||||
Editor.Instance.Scene.ClearRefsToSceneObjects(true);
|
||||
}
|
||||
|
||||
private void OnScriptsReload()
|
||||
{
|
||||
#if !USE_NETCORE
|
||||
// Clear types cache
|
||||
Newtonsoft.Json.JsonSerializer.ClearCache();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnCompilationFailed()
|
||||
{
|
||||
OnFail("Scripts compilation failed");
|
||||
|
||||
@@ -7,6 +7,7 @@ using Real = System.Single;
|
||||
#endif
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
@@ -30,6 +31,13 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
|
||||
// Rotate to match the space (GUI uses upper left corner as a root)
|
||||
Actor.LocalOrientation = Quaternion.Euler(0, -180, -180);
|
||||
var uiControl = new UIControl
|
||||
{
|
||||
Name = "Canvas Scalar",
|
||||
Transform = Actor.Transform,
|
||||
Control = new CanvasScaler()
|
||||
};
|
||||
Root.Spawn(uiControl, Actor);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
/// <summary>
|
||||
/// Starts the actor renaming action.
|
||||
/// </summary>
|
||||
public void StartRenaming(EditorWindow window)
|
||||
public void StartRenaming(EditorWindow window, Panel treePanel = null)
|
||||
{
|
||||
// Block renaming during scripts reload
|
||||
if (Editor.Instance.ProgressReporting.CompileScripts.IsActive)
|
||||
@@ -281,7 +281,13 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
(window as PrefabWindow).ScrollingOnTreeView(false);
|
||||
|
||||
// Start renaming the actor
|
||||
var dialog = RenamePopup.Show(this, TextRect, _actorNode.Name, false);
|
||||
var rect = TextRect;
|
||||
if (treePanel != null)
|
||||
{
|
||||
treePanel.ScrollViewTo(this, true);
|
||||
rect.Size = new Float2(treePanel.Width - TextRect.Location.X, TextRect.Height);
|
||||
}
|
||||
var dialog = RenamePopup.Show(this, rect, _actorNode.Name, false);
|
||||
dialog.Renamed += OnRenamed;
|
||||
dialog.Closed += popup =>
|
||||
{
|
||||
|
||||
@@ -207,9 +207,9 @@ void RiderCodeEditor::FindEditors(Array<CodeEditor*>* output)
|
||||
FileSystem::GetChildDirectories(subDirectories, TEXT("/opt/"));
|
||||
|
||||
// Versions installed via JetBrains Toolbox
|
||||
SearchDirectory(&installations, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/rider/"));
|
||||
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-0"));
|
||||
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-1")); // Beta versions
|
||||
SearchDirectory(&installations, localAppDataPath / TEXT("JetBrains/Toolbox/apps/rider/"));
|
||||
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains/Toolbox/apps/Rider/ch-0"));
|
||||
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains/Toolbox/apps/Rider/ch-1")); // Beta versions
|
||||
|
||||
// Detect Flatpak installations
|
||||
SearchDirectory(&installations,
|
||||
|
||||
@@ -78,7 +78,10 @@ void VisualStudioCodeEditor::FindEditors(Array<CodeEditor*>* output)
|
||||
|
||||
// Detect Flatpak installations
|
||||
{
|
||||
if (Platform::RunProcess(TEXT("/bin/bash -c \"flatpak list --app --columns=application | grep com.visualstudio.code -c\""), String::Empty) == 0)
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = TEXT("/bin/bash -c \"flatpak list --app --columns=application | grep com.visualstudio.code -c\"");
|
||||
procSettings.HiddenWindow = true;
|
||||
if (Platform::CreateProcess(procSettings) == 0)
|
||||
{
|
||||
const String runPath(TEXT("flatpak run com.visualstudio.code"));
|
||||
output->Add(New<VisualStudioCodeEditor>(runPath, false));
|
||||
|
||||
@@ -56,12 +56,14 @@ namespace FlaxEditor.States
|
||||
else if (Editor.Options.Options.General.ForceScriptCompilationOnStartup && !skipCompile)
|
||||
{
|
||||
// Generate project files when Cache is missing or was cleared previously
|
||||
if (!Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Intermediate")) ||
|
||||
!Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Projects")))
|
||||
var projectFolderPath = Editor.GameProject?.ProjectFolderPath;
|
||||
if (!Directory.Exists(Path.Combine(projectFolderPath, "Cache", "Intermediate")) ||
|
||||
!Directory.Exists(Path.Combine(projectFolderPath, "Cache", "Projects")))
|
||||
{
|
||||
var customArgs = Editor.Instance.CodeEditing.SelectedEditor.GenerateProjectCustomArgs;
|
||||
var customArgs = Editor.CodeEditing.SelectedEditor?.GenerateProjectCustomArgs;
|
||||
ScriptsBuilder.GenerateProject(customArgs);
|
||||
}
|
||||
|
||||
// Compile scripts before loading any scenes, then we load them and can open scenes
|
||||
ScriptsBuilder.Compile();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.States
|
||||
|
||||
@@ -465,7 +465,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (selectedIndex != -1)
|
||||
{
|
||||
var index = 5 + selectedIndex * 2;
|
||||
SetValue(index, _animationPicker.SelectedID);
|
||||
SetValue(index, _animationPicker.Validator.SelectedID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
if (isValid)
|
||||
{
|
||||
_animationPicker.SelectedID = data1;
|
||||
_animationPicker.Validator.SelectedID = data1;
|
||||
_animationSpeed.Value = data0.W;
|
||||
|
||||
var path = string.Empty;
|
||||
@@ -505,7 +505,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
else
|
||||
{
|
||||
_animationPicker.SelectedID = Guid.Empty;
|
||||
_animationPicker.Validator.SelectedID = Guid.Empty;
|
||||
_animationSpeed.Value = 1.0f;
|
||||
}
|
||||
_animationPicker.Enabled = isValid;
|
||||
|
||||
@@ -288,6 +288,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
SetValue(2, ids);
|
||||
|
||||
// Force refresh UI
|
||||
ResizeAuto();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Op1(1, "Bitwise NOT", "Negates the value using bitwise operation", new[] { "!", "~" }),
|
||||
Op2(2, "Bitwise AND", "Performs a bitwise conjunction on two values", new[] { "&" }),
|
||||
Op2(3, "Bitwise OR", "", new[] { "|" }),
|
||||
Op2(4, "Bitwise XOR", ""),
|
||||
Op2(4, "Bitwise XOR", "", new[] { "^" }),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Op1(1, "Boolean NOT", "Negates the boolean value", new[] { "!", "~" }),
|
||||
Op2(2, "Boolean AND", "Performs a logical conjunction on two values", new[] { "&&" }),
|
||||
Op2(3, "Boolean OR", "Returns true if either (or both) of its operands is true", new[] { "||" }),
|
||||
Op2(4, "Boolean XOR", ""),
|
||||
Op2(4, "Boolean XOR", "", new [] { "^" } ),
|
||||
Op2(5, "Boolean NOR", ""),
|
||||
Op2(6, "Boolean NAND", ""),
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
[HideInEditor]
|
||||
public static class Comparisons
|
||||
{
|
||||
private static NodeArchetype Op(ushort id, string title, string desc)
|
||||
private static NodeArchetype Op(ushort id, string title, string desc, string[] altTitles = null)
|
||||
{
|
||||
return new NodeArchetype
|
||||
{
|
||||
@@ -22,6 +22,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = title,
|
||||
Description = desc,
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
AlternativeTitles = altTitles,
|
||||
ConnectionsHints = ConnectionsHint.Value,
|
||||
Size = new Float2(100, 40),
|
||||
IndependentBoxes = new[]
|
||||
@@ -170,12 +171,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// </summary>
|
||||
public static NodeArchetype[] Nodes =
|
||||
{
|
||||
Op(1, "==", "Determines whether two values are equal"),
|
||||
Op(2, "!=", "Determines whether two values are not equal"),
|
||||
Op(3, ">", "Determines whether the first value is greater than the other"),
|
||||
Op(4, "<", "Determines whether the first value is less than the other"),
|
||||
Op(5, "<=", "Determines whether the first value is less or equal to the other"),
|
||||
Op(6, ">=", "Determines whether the first value is greater or equal to the other"),
|
||||
Op(1, "==", "Determines whether two values are equal", new[] { "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" }),
|
||||
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" }),
|
||||
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
|
||||
{
|
||||
TypeID = 7,
|
||||
|
||||
@@ -7,11 +7,12 @@ using Real = System.Single;
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Surface.Elements;
|
||||
using FlaxEditor.Surface.Undo;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
@@ -24,6 +25,109 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
[HideInEditor]
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// A special type of node that adds the functionality to convert nodes to parameters.
|
||||
/// </summary>
|
||||
internal class ConvertToParameterNode : SurfaceNode
|
||||
{
|
||||
private readonly ScriptType _type;
|
||||
private readonly Func<object[], object> _convertFunction;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConvertToParameterNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func<object[], object> convertFunction = null)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{
|
||||
_type = type;
|
||||
_convertFunction = convertFunction;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location)
|
||||
{
|
||||
base.OnShowSecondaryContextMenu(menu, location);
|
||||
|
||||
menu.AddSeparator();
|
||||
menu.AddButton("Convert to Parameter", OnConvertToParameter);
|
||||
}
|
||||
|
||||
private void OnConvertToParameter()
|
||||
{
|
||||
if (Surface.Owner is not IVisjectSurfaceWindow window)
|
||||
throw new Exception("Surface owner is not a Visject Surface Window");
|
||||
|
||||
Asset asset = Surface.Owner.SurfaceAsset;
|
||||
if (asset == null || !asset.IsLoaded)
|
||||
{
|
||||
Editor.LogError("Asset is null or not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add parameter to editor
|
||||
var paramIndex = Surface.Parameters.Count;
|
||||
var initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values);
|
||||
var paramAction = new AddRemoveParamAction
|
||||
{
|
||||
Window = window,
|
||||
IsAdd = true,
|
||||
Name = Utilities.Utils.IncrementNameNumber("New parameter", OnParameterRenameValidate),
|
||||
Type = _type,
|
||||
Index = paramIndex,
|
||||
InitValue = initValue,
|
||||
};
|
||||
paramAction.Do();
|
||||
Surface.AddBatchedUndoAction(paramAction);
|
||||
|
||||
// Spawn Get Parameter Node based on the added parameter
|
||||
Guid parameterGuid = Surface.Parameters[paramIndex].ID;
|
||||
bool undoEnabled = Surface.Undo.Enabled;
|
||||
Surface.Undo.Enabled = false;
|
||||
NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId);
|
||||
SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, Location, new object[] { parameterGuid });
|
||||
Surface.Undo.Enabled = undoEnabled;
|
||||
if (node is not Parameters.SurfaceNodeParamsGet getNode)
|
||||
throw new Exception("Node is not a ParamsGet node!");
|
||||
Surface.AddBatchedUndoAction(new AddRemoveNodeAction(getNode, true));
|
||||
|
||||
// Recreate connections of constant node
|
||||
// Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections
|
||||
var editConnectionsAction1 = new EditNodeConnections(Context, this);
|
||||
var editConnectionsAction2 = new EditNodeConnections(Context, node);
|
||||
var boxes = GetBoxes();
|
||||
for (int i = 0; i < boxes.Count; i++)
|
||||
{
|
||||
Box box = boxes[i];
|
||||
if (!box.HasAnyConnection)
|
||||
continue;
|
||||
if (!getNode.TryGetBox(box.ID, out Box paramBox))
|
||||
continue;
|
||||
|
||||
// Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true
|
||||
for (int k = box.Connections.Count - 1; k >= 0; k--)
|
||||
{
|
||||
Box connectedBox = box.Connections[k];
|
||||
paramBox.CreateConnection(connectedBox);
|
||||
}
|
||||
}
|
||||
editConnectionsAction1.End();
|
||||
editConnectionsAction2.End();
|
||||
Surface.AddBatchedUndoAction(editConnectionsAction1);
|
||||
Surface.AddBatchedUndoAction(editConnectionsAction2);
|
||||
|
||||
// Add undo actions and remove constant node
|
||||
var removeConstantAction = new AddRemoveNodeAction(this, false);
|
||||
Surface.AddBatchedUndoAction(removeConstantAction);
|
||||
removeConstantAction.Do();
|
||||
Surface.MarkAsEdited();
|
||||
}
|
||||
|
||||
private bool OnParameterRenameValidate(string value)
|
||||
{
|
||||
if (Surface.Owner is not IVisjectSurfaceWindow window)
|
||||
throw new Exception("Surface owner is not a Visject Surface Window");
|
||||
return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value);
|
||||
}
|
||||
}
|
||||
|
||||
private class EnumNode : SurfaceNode
|
||||
{
|
||||
private EnumComboBox _picker;
|
||||
@@ -356,6 +460,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 1,
|
||||
Title = "Bool",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(bool))),
|
||||
Description = "Constant boolean value",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(110, 20),
|
||||
@@ -388,6 +493,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 2,
|
||||
Title = "Integer",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(int))),
|
||||
Description = "Constant integer value",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(110, 20),
|
||||
@@ -415,6 +521,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 3,
|
||||
Title = "Float",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(float))),
|
||||
Description = "Constant floating point",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(110, 20),
|
||||
@@ -442,6 +549,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 4,
|
||||
Title = "Float2",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))),
|
||||
Description = "Constant Float2",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 60),
|
||||
@@ -472,6 +580,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 5,
|
||||
Title = "Float3",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))),
|
||||
Description = "Constant Float3",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 80),
|
||||
@@ -504,6 +613,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 6,
|
||||
Title = "Float4",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))),
|
||||
Description = "Constant Float4",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 100),
|
||||
@@ -538,6 +648,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 7,
|
||||
Title = "Color",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Color))),
|
||||
Description = "RGBA color",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(70, 100),
|
||||
@@ -570,6 +681,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 8,
|
||||
Title = "Rotation",
|
||||
Create = (id, context, arch, groupArch) =>
|
||||
new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), values => Quaternion.Euler((float)values[0], (float)values[1], (float)values[2])),
|
||||
Description = "Euler angle rotation",
|
||||
Flags = NodeFlags.AnimGraph | NodeFlags.VisualScriptGraph | NodeFlags.ParticleEmitterGraph,
|
||||
Size = new Float2(110, 60),
|
||||
@@ -594,6 +707,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 9,
|
||||
Title = "String",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(string))),
|
||||
Description = "Text",
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph,
|
||||
Size = new Float2(200, 20),
|
||||
@@ -644,6 +758,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 12,
|
||||
Title = "Unsigned Integer",
|
||||
AlternativeTitles = new[] { "UInt", "U Int" },
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(uint))),
|
||||
Description = "Constant unsigned integer value",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(170, 20),
|
||||
@@ -683,6 +799,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 15,
|
||||
Title = "Double",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(double))),
|
||||
Description = "Constant floating point",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(110, 20),
|
||||
@@ -700,6 +817,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 16,
|
||||
Title = "Vector2",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))),
|
||||
Description = "Constant Vector2",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 60),
|
||||
@@ -720,6 +838,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 17,
|
||||
Title = "Vector3",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))),
|
||||
Description = "Constant Vector3",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 80),
|
||||
@@ -742,6 +861,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 18,
|
||||
Title = "Vector4",
|
||||
Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))),
|
||||
Description = "Constant Vector4",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(130, 100),
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
private void OnAssetPickerSelectedItemChanged()
|
||||
{
|
||||
SetValue(0, _assetPicker.SelectedID);
|
||||
SetValue(0, _assetPicker.Validator.SelectedID);
|
||||
}
|
||||
|
||||
private void TryRestoreConnections(Box box, Box[] prevBoxes, ref NodeElementArchetype arch)
|
||||
@@ -133,7 +133,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
var prevOutputs = _outputs;
|
||||
|
||||
// Extract function signature parameters (inputs and outputs packed)
|
||||
_asset = LoadSignature(_assetPicker.SelectedID, out var typeNames, out var names);
|
||||
_asset = LoadSignature(_assetPicker.Validator.SelectedID, out var typeNames, out var names);
|
||||
if (typeNames != null && names != null)
|
||||
{
|
||||
var types = new Type[typeNames.Length];
|
||||
@@ -174,7 +174,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_outputs[i] = box;
|
||||
}
|
||||
|
||||
Title = _assetPicker.SelectedItem.ShortName;
|
||||
Title = _assetPicker.Validator.SelectedItem.ShortName;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2470,6 +2470,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = string.Empty,
|
||||
Description = "Overrides the base class method with custom implementation",
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.NoSpawnViaGUI | NodeFlags.NoSpawnViaPaste,
|
||||
SortScore = 10,
|
||||
IsInputCompatible = MethodOverrideNode.IsInputCompatible,
|
||||
IsOutputCompatible = MethodOverrideNode.IsOutputCompatible,
|
||||
Size = new Float2(240, 60),
|
||||
|
||||
@@ -882,6 +882,60 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(1, "Inv Size", typeof(Float2), 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 40,
|
||||
Title = "Rectangle Mask",
|
||||
Description = "Creates a rectangle mask",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(150, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
new Float2(0.5f, 0.5f),
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Rectangle", true, typeof(Float2), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 41,
|
||||
Title = "FWidth",
|
||||
Description = "Creates a partial derivative (fwidth)",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(150, 20),
|
||||
ConnectionsHints = ConnectionsHint.Numeric,
|
||||
IndependentBoxes = new[] { 0 },
|
||||
DependentBoxes = new[] { 1 },
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 42,
|
||||
Title = "AA Step",
|
||||
Description = "Smooth version of step function with less aliasing",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(150, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
0.5f
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Gradient", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public static class Math
|
||||
{
|
||||
private static NodeArchetype Op1(ushort id, string title, string desc, ConnectionsHint hints = ConnectionsHint.Numeric, Type type = null)
|
||||
{
|
||||
return Op1(id, title, desc, null, hints, type);
|
||||
}
|
||||
|
||||
private static NodeArchetype Op1(ushort id, string title, string desc, string[] altTitles, ConnectionsHint hints = ConnectionsHint.Numeric, Type type = null)
|
||||
{
|
||||
return new NodeArchetype
|
||||
{
|
||||
@@ -20,6 +25,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = title,
|
||||
Description = desc,
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
AlternativeTitles = altTitles,
|
||||
Size = new Float2(110, 20),
|
||||
DefaultType = new ScriptType(type),
|
||||
ConnectionsHints = hints,
|
||||
@@ -92,6 +98,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 11,
|
||||
Title = "Length",
|
||||
AlternativeTitles = new[] { "Magnitude", "Mag" },
|
||||
Description = "Returns the length of A vector",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(110, 20),
|
||||
@@ -107,10 +114,10 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Op1(13, "Round", "Rounds A to the nearest integer"),
|
||||
Op1(14, "Saturate", "Clamps A to the range [0, 1]"),
|
||||
Op1(15, "Sine", "Returns sine of A"),
|
||||
Op1(16, "Sqrt", "Returns square root of A"),
|
||||
Op1(16, "Sqrt", "Returns square root of A", new [] { "Square Root", "Square", "Root" }),
|
||||
Op1(17, "Tangent", "Returns tangent of A"),
|
||||
Op2(18, "Cross", "Returns the cross product of A and B", ConnectionsHint.None, typeof(Float3)),
|
||||
Op2(19, "Distance", "Returns a distance scalar between A and B", ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(19, "Distance", "Returns a distance scalar between A and B", new [] { "Magnitude", "Mag", "Length" }, ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(20, "Dot", "Returns the dot product of A and B", ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(21, "Max", "Selects the greater of A and B"),
|
||||
Op2(22, "Min", "Selects the lesser of A and B"),
|
||||
@@ -185,7 +192,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
},
|
||||
//
|
||||
Op1(27, "Negate", "Returns opposite value"),
|
||||
Op1(27, "Negate", "Returns opposite value", new [] { "Invert" }),
|
||||
Op1(28, "One Minus", "Returns 1 - value"),
|
||||
//
|
||||
new NodeArchetype
|
||||
@@ -225,6 +232,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 31,
|
||||
Title = "Mad",
|
||||
AlternativeTitles = new [] { "Multiply", "Add", "*+" },
|
||||
Description = "Performs value multiplication and addition at once",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(160, 60),
|
||||
|
||||
@@ -1084,7 +1084,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
||||
NodeElementArchetype.Factory.Input(0, string.Empty, false, typeof(void), 0),
|
||||
NodeElementArchetype.Factory.Input(1, string.Empty, true, ScriptType.Null, 1, 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(void), 2, true),
|
||||
NodeElementArchetype.Factory.ComboBox(2 + 20, 0, 116)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface.Archetypes
|
||||
@@ -95,6 +96,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 1,
|
||||
Title = "Texture",
|
||||
Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))),
|
||||
Description = "Two dimensional texture object",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(140, 120),
|
||||
@@ -131,6 +133,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 3,
|
||||
Title = "Cube Texture",
|
||||
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",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(140, 120),
|
||||
@@ -154,6 +157,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 4,
|
||||
Title = "Normal Map",
|
||||
Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))),
|
||||
Description = "Two dimensional texture object sampled as a normal map",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(140, 120),
|
||||
|
||||
@@ -1483,7 +1483,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 11,
|
||||
Title = "Comment",
|
||||
AlternativeTitles = new[] { "//" },
|
||||
AlternativeTitles = new[] { "//" , "Group" },
|
||||
TryParseText = (string filterText, out object[] data) =>
|
||||
{
|
||||
data = null;
|
||||
@@ -1510,6 +1510,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
"Comment", // Title
|
||||
new Color(1.0f, 1.0f, 1.0f, 0.2f), // Color
|
||||
new Float2(400.0f, 400.0f), // Size
|
||||
-1, // Order
|
||||
},
|
||||
},
|
||||
CurveNode<float>.GetArchetype(12, "Curve", typeof(float), 0.0f, 1.0f),
|
||||
@@ -1638,6 +1639,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 22,
|
||||
Title = "As",
|
||||
AlternativeTitles = new [] { "Cast" },
|
||||
Create = (id, context, arch, groupArch) => new AsNode(id, context, arch, groupArch),
|
||||
Description = "Casts the object to a different type. Returns null if cast fails.",
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph,
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
SortScore += _archetype.SortScore;
|
||||
if (selectedBox != null && CanConnectTo(selectedBox))
|
||||
SortScore += 1;
|
||||
if (Data != null)
|
||||
|
||||
@@ -38,13 +38,13 @@ namespace FlaxEditor.Surface.Elements
|
||||
|
||||
private void OnNodeValuesChanged()
|
||||
{
|
||||
SelectedID = (Guid)ParentNode.Values[Archetype.ValueIndex];
|
||||
Validator.SelectedID = (Guid)ParentNode.Values[Archetype.ValueIndex];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSelectedItemChanged()
|
||||
{
|
||||
var selectedId = SelectedID;
|
||||
var selectedId = Validator.SelectedID;
|
||||
if (ParentNode != null && (Guid)ParentNode.Values[Archetype.ValueIndex] != selectedId)
|
||||
{
|
||||
ParentNode.SetValue(Archetype.ValueIndex, selectedId);
|
||||
|
||||
@@ -149,6 +149,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public object Tag;
|
||||
|
||||
/// <summary>
|
||||
/// Custom score value to use when sorting node archetypes in Editor. If positive (eg. 1, 2) can be used to add more importance for a specific node type.
|
||||
/// </summary>
|
||||
public float SortScore;
|
||||
|
||||
/// <summary>
|
||||
/// Default node values. This array supports types: bool, int, float, Vector2, Vector3, Vector4, Color, Rectangle, Guid, string, Matrix and byte[].
|
||||
/// </summary>
|
||||
@@ -204,14 +209,17 @@ namespace FlaxEditor.Surface
|
||||
Size = Size,
|
||||
Flags = Flags,
|
||||
Title = Title,
|
||||
Description = Title,
|
||||
SubTitle = SubTitle,
|
||||
Description = Description,
|
||||
AlternativeTitles = (string[])AlternativeTitles?.Clone(),
|
||||
Tag = Tag,
|
||||
SortScore = SortScore,
|
||||
DefaultValues = (object[])DefaultValues?.Clone(),
|
||||
DefaultType = DefaultType,
|
||||
ConnectionsHints = ConnectionsHints,
|
||||
IndependentBoxes = (int[])IndependentBoxes?.Clone(),
|
||||
DependentBoxes = (int[])DependentBoxes?.Clone(),
|
||||
DependentBoxFilter = DependentBoxFilter,
|
||||
Elements = (NodeElementArchetype[])Elements?.Clone(),
|
||||
TryParseText = TryParseText,
|
||||
};
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
{
|
||||
groupId = 6;
|
||||
return Archetypes.Parameters.Nodes[1];
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -52,6 +53,12 @@ namespace FlaxEditor.Surface
|
||||
set => SetValue(2, value, false);
|
||||
}
|
||||
|
||||
private int OrderValue
|
||||
{
|
||||
get => (int)Values[3];
|
||||
set => SetValue(3, value, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public SurfaceComment(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
@@ -67,6 +74,19 @@ namespace FlaxEditor.Surface
|
||||
Title = TitleValue;
|
||||
Color = ColorValue;
|
||||
Size = SizeValue;
|
||||
|
||||
// Order
|
||||
// Backwards compatibility - When opening with an older version send the old comments to the back
|
||||
if (Values.Length < 4)
|
||||
{
|
||||
if (IndexInParent > 0)
|
||||
IndexInParent = 0;
|
||||
OrderValue = IndexInParent;
|
||||
}
|
||||
else if(OrderValue != -1)
|
||||
{
|
||||
IndexInParent = OrderValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -76,6 +96,10 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Randomize color
|
||||
Color = ColorValue = Color.FromHSV(new Random().NextFloat(0, 360), 0.7f, 0.25f, 0.8f);
|
||||
|
||||
if(OrderValue == -1)
|
||||
OrderValue = Context.CommentCount - 1;
|
||||
IndexInParent = OrderValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -314,5 +338,38 @@ namespace FlaxEditor.Surface
|
||||
Color = ColorValue = color;
|
||||
Surface.MarkAsEdited(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location)
|
||||
{
|
||||
base.OnShowSecondaryContextMenu(menu, location);
|
||||
|
||||
menu.AddSeparator();
|
||||
ContextMenuChildMenu cmOrder = menu.AddChildMenu("Order");
|
||||
{
|
||||
cmOrder.ContextMenu.AddButton("Bring Forward", () =>
|
||||
{
|
||||
if(IndexInParent < Context.CommentCount-1)
|
||||
IndexInParent++;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
cmOrder.ContextMenu.AddButton("Bring to Front", () =>
|
||||
{
|
||||
IndexInParent = Context.CommentCount-1;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
cmOrder.ContextMenu.AddButton("Send Backward", () =>
|
||||
{
|
||||
if(IndexInParent > 0)
|
||||
IndexInParent--;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
cmOrder.ContextMenu.AddButton("Send to Back", () =>
|
||||
{
|
||||
IndexInParent = 0;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
{
|
||||
@@ -27,7 +26,7 @@ namespace FlaxEditor.Surface
|
||||
/// <summary>
|
||||
/// Parameter unique ID
|
||||
/// </summary>
|
||||
public Guid ID;
|
||||
public Guid ID = Guid.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter name
|
||||
@@ -49,23 +48,5 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
[NoSerialize, HideInEditor]
|
||||
public readonly SurfaceMeta Meta = new SurfaceMeta();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new parameter of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>The created parameter.</returns>
|
||||
public static SurfaceParameter Create(ScriptType type, string name)
|
||||
{
|
||||
return new SurfaceParameter
|
||||
{
|
||||
ID = Guid.NewGuid(),
|
||||
IsPublic = true,
|
||||
Name = name,
|
||||
Type = type,
|
||||
Value = TypeUtils.GetDefaultValue(type),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
/// <param name="groupId">The group ID.</param>
|
||||
/// <returns>The node archetype.</returns>
|
||||
protected virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
protected internal virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
{
|
||||
groupId = 6;
|
||||
return Archetypes.Parameters.Nodes[0];
|
||||
|
||||
@@ -716,7 +716,18 @@ namespace FlaxEditor.Surface
|
||||
return null;
|
||||
Rectangle surfaceArea = GetNodesBounds(selection).MakeExpanded(80.0f);
|
||||
|
||||
return _context.CreateComment(ref surfaceArea, string.IsNullOrEmpty(text) ? "Comment" : text, new Color(1.0f, 1.0f, 1.0f, 0.2f));
|
||||
// Order below other selected comments
|
||||
bool hasCommentsSelected = false;
|
||||
int lowestCommentOrder = int.MaxValue;
|
||||
for (int i = 0; i < selection.Count; i++)
|
||||
{
|
||||
if (selection[i] is not SurfaceComment || selection[i].IndexInParent >= lowestCommentOrder)
|
||||
continue;
|
||||
hasCommentsSelected = true;
|
||||
lowestCommentOrder = selection[i].IndexInParent;
|
||||
}
|
||||
|
||||
return _context.CreateComment(ref surfaceArea, string.IsNullOrEmpty(text) ? "Comment" : text, new Color(1.0f, 1.0f, 1.0f, 0.2f), hasCommentsSelected ? lowestCommentOrder : -1);
|
||||
}
|
||||
|
||||
private static Rectangle GetNodesBounds(List<SurfaceNode> nodes)
|
||||
|
||||
@@ -920,12 +920,6 @@ namespace FlaxEditor.Surface
|
||||
// Link control
|
||||
control.OnLoaded(action);
|
||||
control.Parent = RootControl;
|
||||
|
||||
if (control is SurfaceComment)
|
||||
{
|
||||
// Move comments to the background
|
||||
control.IndexInParent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -85,6 +85,27 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of surface comments
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is used as an alternative to <see cref="Comments"/>, if only the amount of comments is important.
|
||||
/// Is faster and doesn't allocate as much memory
|
||||
/// </remarks>
|
||||
public int CommentCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < RootControl.Children.Count; i++)
|
||||
{
|
||||
if (RootControl.Children[i] is SurfaceComment)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this context is modified (needs saving and flushing with surface data context source).
|
||||
/// </summary>
|
||||
@@ -285,14 +306,16 @@ namespace FlaxEditor.Surface
|
||||
/// <param name="surfaceArea">The surface area to create comment.</param>
|
||||
/// <param name="title">The comment title.</param>
|
||||
/// <param name="color">The comment color.</param>
|
||||
/// <param name="customOrder">The comment order or -1 to use default.</param>
|
||||
/// <returns>The comment object</returns>
|
||||
public virtual SurfaceComment SpawnComment(ref Rectangle surfaceArea, string title, Color color)
|
||||
public virtual SurfaceComment SpawnComment(ref Rectangle surfaceArea, string title, Color color, int customOrder = -1)
|
||||
{
|
||||
var values = new object[]
|
||||
{
|
||||
title, // Title
|
||||
color, // Color
|
||||
surfaceArea.Size, // Size
|
||||
customOrder, // Order
|
||||
};
|
||||
return (SurfaceComment)SpawnNode(7, 11, surfaceArea.Location, values);
|
||||
}
|
||||
@@ -303,11 +326,12 @@ namespace FlaxEditor.Surface
|
||||
/// <param name="surfaceArea">The surface area to create comment.</param>
|
||||
/// <param name="title">The comment title.</param>
|
||||
/// <param name="color">The comment color.</param>
|
||||
/// <param name="customOrder">The comment order or -1 to use default.</param>
|
||||
/// <returns>The comment object</returns>
|
||||
public SurfaceComment CreateComment(ref Rectangle surfaceArea, string title, Color color)
|
||||
public SurfaceComment CreateComment(ref Rectangle surfaceArea, string title, Color color, int customOrder = -1)
|
||||
{
|
||||
// Create comment
|
||||
var comment = SpawnComment(ref surfaceArea, title, color);
|
||||
var comment = SpawnComment(ref surfaceArea, title, color, customOrder);
|
||||
if (comment == null)
|
||||
{
|
||||
Editor.LogWarning("Failed to create comment.");
|
||||
|
||||
@@ -17,6 +17,7 @@ using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
{
|
||||
@@ -258,6 +259,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public IVisjectSurfaceWindow Window;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier of the parameter. Empty to auto generate it.
|
||||
/// </summary>
|
||||
public Guid Id = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// True if adding, false if removing parameter.
|
||||
/// </summary>
|
||||
@@ -278,6 +284,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public ScriptType Type;
|
||||
|
||||
/// <summary>
|
||||
/// The value to initialize the parameter with. Can be null to use default one for the parameter type.
|
||||
/// </summary>
|
||||
public object InitValue;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => IsAdd ? "Add parameter" : "Remove parameter";
|
||||
|
||||
@@ -304,7 +315,14 @@ namespace FlaxEditor.Surface
|
||||
var type = Type;
|
||||
if (IsAdd && type.Type == typeof(NormalMap))
|
||||
type = new ScriptType(typeof(Texture));
|
||||
var param = SurfaceParameter.Create(type, Name);
|
||||
var param = new SurfaceParameter
|
||||
{
|
||||
ID = Id,
|
||||
IsPublic = true,
|
||||
Name = Name,
|
||||
Type = type,
|
||||
Value = InitValue ?? TypeUtils.GetDefaultValue(type),
|
||||
};
|
||||
if (IsAdd && Type.Type == typeof(NormalMap))
|
||||
param.Value = FlaxEngine.Content.LoadAsyncInternal<Texture>("Engine/Textures/NormalTexture");
|
||||
Window.VisjectSurface.Parameters.Insert(Index, param);
|
||||
@@ -725,6 +743,8 @@ namespace FlaxEditor.Surface
|
||||
protected VisjectSurfaceWindow(Editor editor, AssetItem item, bool useTabs = false)
|
||||
: base(editor, item)
|
||||
{
|
||||
var inputOptions = Editor.Options.Options.Input;
|
||||
|
||||
// Undo
|
||||
_undo = new FlaxEditor.Undo();
|
||||
_undo.UndoDone += OnUndoRedo;
|
||||
@@ -775,10 +795,10 @@ namespace FlaxEditor.Surface
|
||||
// Toolstrip
|
||||
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
|
||||
_toolstrip.AddSeparator();
|
||||
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
|
||||
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
|
||||
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip($"Undo ({inputOptions.Undo})");
|
||||
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip($"Redo ({inputOptions.Redo})");
|
||||
_toolstrip.AddSeparator();
|
||||
_toolstrip.AddButton(Editor.Icons.Search64, Editor.ContentFinding.ShowSearch).LinkTooltip("Open content search tool (Ctrl+F)");
|
||||
_toolstrip.AddButton(Editor.Icons.Search64, Editor.ContentFinding.ShowSearch).LinkTooltip($"Open content search tool ({inputOptions.Search})");
|
||||
_toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
|
||||
|
||||
// Setup input actions
|
||||
@@ -1058,7 +1078,6 @@ namespace FlaxEditor.Surface
|
||||
public virtual void OnParamRemoveUndo()
|
||||
{
|
||||
_refreshPropertiesOnLoad = true;
|
||||
//_propertiesEditor.BuildLayoutOnUpdate();
|
||||
_propertiesEditor.BuildLayout();
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
|
||||
{
|
||||
groupId = 6;
|
||||
return Archetypes.Parameters.Nodes[2];
|
||||
|
||||
@@ -18,21 +18,25 @@ namespace FlaxEngine.Tools
|
||||
/// <summary>
|
||||
/// Brush radius (world-space).
|
||||
/// </summary>
|
||||
[Limit(0)]
|
||||
public float BrushSize = 50.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Brush paint intensity.
|
||||
/// </summary>
|
||||
[Limit(0)]
|
||||
public float BrushStrength = 2.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Brush paint falloff. Hardens or softens painting.
|
||||
/// </summary>
|
||||
[Limit(0)]
|
||||
public float BrushFalloff = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Value to paint with. Hold Ctrl hey to paint with inverse value (1 - value).
|
||||
/// </summary>
|
||||
[Limit(0, 1, 0.01f)]
|
||||
public float PaintValue = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
@@ -225,6 +229,7 @@ namespace FlaxEngine.Tools
|
||||
var cloth = _cloth;
|
||||
if (cloth == null)
|
||||
return;
|
||||
var hasPaintInput = Owner.IsLeftMouseButtonDown && !Owner.IsAltKeyDown;
|
||||
|
||||
// Perform detailed tracing to find cursor location for the brush
|
||||
var ray = Owner.MouseRay;
|
||||
@@ -240,7 +245,7 @@ namespace FlaxEngine.Tools
|
||||
// Cursor hit other object or nothing
|
||||
PaintEnd();
|
||||
|
||||
if (Owner.IsLeftMouseButtonDown)
|
||||
if (hasPaintInput)
|
||||
{
|
||||
// Select something else
|
||||
var view = new Ray(Owner.ViewPosition, Owner.ViewDirection);
|
||||
@@ -253,7 +258,7 @@ namespace FlaxEngine.Tools
|
||||
}
|
||||
|
||||
// Handle painting
|
||||
if (Owner.IsLeftMouseButtonDown)
|
||||
if (hasPaintInput)
|
||||
PaintStart();
|
||||
else
|
||||
PaintEnd();
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace FlaxEditor.Tools.Terrain
|
||||
|
||||
var patchCoord = Gizmo.SelectedPatchCoord;
|
||||
var chunkCoord = Gizmo.SelectedChunkCoord;
|
||||
var action = new EditChunkMaterialAction(CarveTab.SelectedTerrain, ref patchCoord, ref chunkCoord, _chunkOverrideMaterial.SelectedAsset as MaterialBase);
|
||||
var action = new EditChunkMaterialAction(CarveTab.SelectedTerrain, ref patchCoord, ref chunkCoord, _chunkOverrideMaterial.Validator.SelectedAsset as MaterialBase);
|
||||
action.Do();
|
||||
CarveTab.Editor.Undo.AddAction(action);
|
||||
}
|
||||
@@ -336,12 +336,12 @@ namespace FlaxEditor.Tools.Terrain
|
||||
_isUpdatingUI = true;
|
||||
if (terrain.HasPatch(ref patchCoord))
|
||||
{
|
||||
_chunkOverrideMaterial.SelectedAsset = terrain.GetChunkOverrideMaterial(ref patchCoord, ref chunkCoord);
|
||||
_chunkOverrideMaterial.Validator.SelectedAsset = terrain.GetChunkOverrideMaterial(ref patchCoord, ref chunkCoord);
|
||||
_chunkOverrideMaterial.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_chunkOverrideMaterial.SelectedAsset = null;
|
||||
_chunkOverrideMaterial.Validator.SelectedAsset = null;
|
||||
_chunkOverrideMaterial.Enabled = false;
|
||||
}
|
||||
_isUpdatingUI = false;
|
||||
|
||||
@@ -86,6 +86,9 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public abstract void Select(List<SceneGraphNode> nodes);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void Spawn(Actor actor);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ using System.Collections.Generic;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Viewport.Cameras;
|
||||
using FlaxEditor.Viewport.Modes;
|
||||
@@ -37,28 +35,8 @@ namespace FlaxEditor.Viewport
|
||||
private readonly ViewportWidgetButton _rotateSnapping;
|
||||
private readonly ViewportWidgetButton _scaleSnapping;
|
||||
|
||||
private readonly DragAssets<DragDropEventArgs> _dragAssets;
|
||||
private readonly DragActorType<DragDropEventArgs> _dragActorType = new DragActorType<DragDropEventArgs>(ValidateDragActorType);
|
||||
|
||||
private SelectionOutline _customSelectionOutline;
|
||||
|
||||
/// <summary>
|
||||
/// The custom drag drop event arguments.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.GUI.Drag.DragEventArgs" />
|
||||
public class DragDropEventArgs : DragEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The hit.
|
||||
/// </summary>
|
||||
public SceneGraphNode Hit;
|
||||
|
||||
/// <summary>
|
||||
/// The hit location.
|
||||
/// </summary>
|
||||
public Vector3 HitLocation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The editor sprites rendering effect.
|
||||
/// </summary>
|
||||
@@ -137,15 +115,12 @@ namespace FlaxEditor.Viewport
|
||||
private bool _lockedFocus;
|
||||
private double _lockedFocusOffset;
|
||||
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
|
||||
private StaticModel _previewStaticModel;
|
||||
private int _previewModelEntryIndex;
|
||||
private BrushSurface _previewBrushSurface;
|
||||
private EditorSpritesRenderer _editorSpritesRenderer;
|
||||
|
||||
/// <summary>
|
||||
/// Drag and drop handlers
|
||||
/// </summary>
|
||||
public readonly DragHandlers DragHandlers = new DragHandlers();
|
||||
public readonly ViewportDragHandlers DragHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// The transform gizmo.
|
||||
@@ -219,7 +194,7 @@ namespace FlaxEditor.Viewport
|
||||
: base(Object.New<SceneRenderTask>(), editor.Undo, editor.Scene.Root)
|
||||
{
|
||||
_editor = editor;
|
||||
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
||||
DragHandlers = new ViewportDragHandlers(this, this, ValidateDragItem, ValidateDragActorType);
|
||||
var inputOptions = editor.Options.Options.Input;
|
||||
|
||||
// Prepare rendering task
|
||||
@@ -408,9 +383,6 @@ namespace FlaxEditor.Viewport
|
||||
ViewWidgetButtonMenu.AddSeparator();
|
||||
ViewWidgetButtonMenu.AddButton("Create camera here", CreateCameraAtView);
|
||||
|
||||
DragHandlers.Add(_dragActorType);
|
||||
DragHandlers.Add(_dragAssets);
|
||||
|
||||
// Init gizmo modes
|
||||
{
|
||||
// Add default modes used by the editor
|
||||
@@ -430,7 +402,11 @@ namespace FlaxEditor.Viewport
|
||||
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||
InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
|
||||
InputActions.Add(options => options.ToggleTransformSpace, () =>
|
||||
{
|
||||
OnTransformSpaceToggle(transformSpaceToggle);
|
||||
transformSpaceToggle.Checked = !transformSpaceToggle.Checked;
|
||||
});
|
||||
InputActions.Add(options => options.LockFocusSelection, LockFocusSelection);
|
||||
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
||||
InputActions.Add(options => options.RotateSelection, RotateSelection);
|
||||
@@ -530,20 +506,9 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private void OnCollectDrawCalls(ref RenderContext renderContext)
|
||||
{
|
||||
if (_previewStaticModel)
|
||||
{
|
||||
_debugDrawData.HighlightModel(_previewStaticModel, _previewModelEntryIndex);
|
||||
}
|
||||
if (_previewBrushSurface.Brush != null)
|
||||
{
|
||||
_debugDrawData.HighlightBrushSurface(_previewBrushSurface);
|
||||
}
|
||||
|
||||
DragHandlers.CollectDrawCalls(_debugDrawData, ref renderContext);
|
||||
if (ShowNavigation)
|
||||
{
|
||||
Editor.Internal_DrawNavMesh();
|
||||
}
|
||||
|
||||
_debugDrawData.OnDraw(ref renderContext);
|
||||
}
|
||||
|
||||
@@ -942,78 +907,14 @@ namespace FlaxEditor.Viewport
|
||||
base.OnLeftMouseButtonUp();
|
||||
}
|
||||
|
||||
private void GetHitLocation(ref Float2 location, out SceneGraphNode hit, out Vector3 hitLocation, out Vector3 hitNormal)
|
||||
{
|
||||
// Get mouse ray and try to hit any object
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
var view = new Ray(ViewPosition, ViewDirection);
|
||||
var gridPlane = new Plane(Vector3.Zero, Vector3.Up);
|
||||
var flags = SceneGraphNode.RayCastData.FlagTypes.SkipColliders | SceneGraphNode.RayCastData.FlagTypes.SkipEditorPrimitives;
|
||||
hit = Editor.Instance.Scene.Root.RayCast(ref ray, ref view, out var closest, out var normal, flags);
|
||||
if (hit != null)
|
||||
{
|
||||
// Use hit location
|
||||
hitLocation = ray.Position + ray.Direction * closest;
|
||||
hitNormal = normal;
|
||||
}
|
||||
else if (Grid.Enabled && CollisionsHelper.RayIntersectsPlane(ref ray, ref gridPlane, out closest) && closest < 4000.0f)
|
||||
{
|
||||
// Use grid location
|
||||
hitLocation = ray.Position + ray.Direction * closest;
|
||||
hitNormal = Vector3.Up;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use area in front of the viewport
|
||||
hitLocation = ViewPosition + ViewDirection * 100;
|
||||
hitNormal = Vector3.Up;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDragEffects(ref Float2 location)
|
||||
{
|
||||
if (_dragAssets.HasValidDrag && _dragAssets.Objects[0].IsOfType<MaterialBase>())
|
||||
{
|
||||
GetHitLocation(ref location, out var hit, out _, out _);
|
||||
ClearDragEffects();
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(_dragAssets.Objects[0].ID);
|
||||
if (material.IsDecal)
|
||||
return;
|
||||
|
||||
if (hit is StaticModelNode staticModelNode)
|
||||
{
|
||||
_previewStaticModel = (StaticModel)staticModelNode.Actor;
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
_previewStaticModel.IntersectsEntry(ref ray, out _, out _, out _previewModelEntryIndex);
|
||||
}
|
||||
else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
|
||||
{
|
||||
_previewBrushSurface = brushSurfaceNode.Surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearDragEffects()
|
||||
{
|
||||
_previewStaticModel = null;
|
||||
_previewModelEntryIndex = -1;
|
||||
_previewBrushSurface = new BrushSurface();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
|
||||
{
|
||||
ClearDragEffects();
|
||||
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragEnter(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
result = DragHandlers.OnDragEnter(data);
|
||||
|
||||
SetDragEffects(ref location);
|
||||
|
||||
return result;
|
||||
return DragHandlers.DragEnter(ref location, data);
|
||||
}
|
||||
|
||||
private bool ValidateDragItem(ContentItem contentItem)
|
||||
@@ -1042,167 +943,29 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
ClearDragEffects();
|
||||
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
SetDragEffects(ref location);
|
||||
|
||||
return DragHandlers.Effect;
|
||||
return DragHandlers.DragEnter(ref location, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
ClearDragEffects();
|
||||
|
||||
DragHandlers.ClearDragEffects();
|
||||
DragHandlers.OnDragLeave();
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
private Vector3 PostProcessSpawnedActorLocation(Actor actor, ref Vector3 hitLocation)
|
||||
{
|
||||
// Refresh actor position to ensure that cached bounds are valid
|
||||
actor.Position = Vector3.One;
|
||||
actor.Position = Vector3.Zero;
|
||||
|
||||
// Place the object
|
||||
//var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection;
|
||||
var editorBounds = actor.EditorBoxChildren;
|
||||
var bottomToCenter = actor.Position.Y - editorBounds.Minimum.Y;
|
||||
var location = hitLocation + new Vector3(0, bottomToCenter, 0);
|
||||
|
||||
// Apply grid snapping if enabled
|
||||
if (UseSnapping || TransformGizmo.TranslationSnapEnable)
|
||||
{
|
||||
float snapValue = TransformGizmo.TranslationSnapValue;
|
||||
location = new Vector3(
|
||||
(int)(location.X / snapValue) * snapValue,
|
||||
(int)(location.Y / snapValue) * snapValue,
|
||||
(int)(location.Z / snapValue) * snapValue);
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
private void Spawn(Actor actor, ref Vector3 hitLocation, ref Vector3 hitNormal)
|
||||
{
|
||||
actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation);
|
||||
var parent = actor.Parent ?? Level.GetScene(0);
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
|
||||
Editor.Instance.SceneEditing.Spawn(actor);
|
||||
Focus();
|
||||
}
|
||||
|
||||
private void Spawn(AssetItem item, SceneGraphNode hit, ref Float2 location, ref Vector3 hitLocation, ref Vector3 hitNormal)
|
||||
{
|
||||
if (item.IsOfType<MaterialBase>())
|
||||
{
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
|
||||
if (material && !material.WaitForLoaded(100) && material.IsDecal)
|
||||
{
|
||||
var actor = new Decal
|
||||
{
|
||||
Material = material,
|
||||
LocalOrientation = RootNode.RaycastNormalRotation(ref hitNormal),
|
||||
Name = item.ShortName
|
||||
};
|
||||
DebugDraw.DrawWireArrow(PostProcessSpawnedActorLocation(actor, ref hitNormal), actor.LocalOrientation, 1.0f, Color.Red, 1000000);
|
||||
Spawn(actor, ref hitLocation, ref hitNormal);
|
||||
}
|
||||
else if (hit is StaticModelNode staticModelNode)
|
||||
{
|
||||
var staticModel = (StaticModel)staticModelNode.Actor;
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
|
||||
{
|
||||
using (new UndoBlock(Undo, staticModel, "Change material"))
|
||||
staticModel.SetMaterial(entryIndex, material);
|
||||
}
|
||||
}
|
||||
else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
|
||||
{
|
||||
using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
|
||||
{
|
||||
var surface = brushSurfaceNode.Surface;
|
||||
surface.Material = material;
|
||||
brushSurfaceNode.Surface = surface;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (item.IsOfType<SceneAsset>())
|
||||
{
|
||||
Editor.Instance.Scene.OpenScene(item.ID, true);
|
||||
return;
|
||||
}
|
||||
{
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation, ref hitNormal);
|
||||
}
|
||||
}
|
||||
|
||||
private void Spawn(ScriptType item, SceneGraphNode hit, ref Float2 location, ref Vector3 hitLocation, ref Vector3 hitNormal)
|
||||
{
|
||||
var actor = item.CreateInstance() as Actor;
|
||||
if (actor == null)
|
||||
{
|
||||
Editor.LogWarning("Failed to spawn actor of type " + item.TypeName);
|
||||
return;
|
||||
}
|
||||
actor.Name = item.Name;
|
||||
Spawn(actor, ref hitLocation, ref hitNormal);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
|
||||
{
|
||||
ClearDragEffects();
|
||||
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragDrop(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
// Check if drag sth
|
||||
Vector3 hitLocation = ViewPosition, hitNormal = -ViewDirection;
|
||||
SceneGraphNode hit = null;
|
||||
if (DragHandlers.HasValidDrag)
|
||||
{
|
||||
GetHitLocation(ref location, out hit, out hitLocation, out hitNormal);
|
||||
}
|
||||
|
||||
// Drag assets
|
||||
if (_dragAssets.HasValidDrag)
|
||||
{
|
||||
result = _dragAssets.Effect;
|
||||
|
||||
// Process items
|
||||
for (int i = 0; i < _dragAssets.Objects.Count; i++)
|
||||
{
|
||||
var item = _dragAssets.Objects[i];
|
||||
Spawn(item, hit, ref location, ref hitLocation, ref hitNormal);
|
||||
}
|
||||
}
|
||||
// Drag actor type
|
||||
else if (_dragActorType.HasValidDrag)
|
||||
{
|
||||
result = _dragActorType.Effect;
|
||||
|
||||
// Process items
|
||||
for (int i = 0; i < _dragActorType.Objects.Count; i++)
|
||||
{
|
||||
var item = _dragActorType.Objects[i];
|
||||
Spawn(item, hit, ref location, ref hitLocation, ref hitNormal);
|
||||
}
|
||||
}
|
||||
|
||||
DragHandlers.OnDragDrop(new DragDropEventArgs { Hit = hit, HitLocation = hitLocation });
|
||||
|
||||
return result;
|
||||
return DragHandlers.DragDrop(ref location, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1211,6 +974,14 @@ namespace FlaxEditor.Viewport
|
||||
_editor.SceneEditing.Select(nodes);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Spawn(Actor actor)
|
||||
{
|
||||
var parent = actor.Parent ?? Level.GetScene(0);
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
|
||||
Editor.Instance.SceneEditing.Spawn(actor);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -5,9 +5,7 @@ using System.Collections.Generic;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Viewport.Cameras;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
@@ -56,9 +54,11 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
|
||||
private PrefabSpritesRenderer _spritesRenderer;
|
||||
private readonly DragAssets _dragAssets;
|
||||
private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType);
|
||||
private readonly DragHandlers _dragHandlers = new DragHandlers();
|
||||
|
||||
/// <summary>
|
||||
/// Drag and drop handlers
|
||||
/// </summary>
|
||||
public readonly ViewportDragHandlers DragHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// The transform gizmo.
|
||||
@@ -81,7 +81,7 @@ namespace FlaxEditor.Viewport
|
||||
_window.SelectionChanged += OnSelectionChanged;
|
||||
Undo = window.Undo;
|
||||
ViewportCamera = new FPSCamera();
|
||||
_dragAssets = new DragAssets(ValidateDragItem);
|
||||
DragHandlers = new ViewportDragHandlers(this, this, ValidateDragItem, ValidateDragActorType);
|
||||
ShowDebugDraw = true;
|
||||
ShowEditorPrimitives = true;
|
||||
Gizmos = new GizmosCollection(this);
|
||||
@@ -228,14 +228,15 @@ namespace FlaxEditor.Viewport
|
||||
_gizmoModeScale.Toggled += OnGizmoModeToggle;
|
||||
gizmoMode.Parent = this;
|
||||
|
||||
_dragHandlers.Add(_dragActorType);
|
||||
_dragHandlers.Add(_dragAssets);
|
||||
|
||||
// Setup input actions
|
||||
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||
InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
|
||||
InputActions.Add(options => options.ToggleTransformSpace, () =>
|
||||
{
|
||||
OnTransformSpaceToggle(transformSpaceToggle);
|
||||
transformSpaceToggle.Checked = !transformSpaceToggle.Checked;
|
||||
});
|
||||
InputActions.Add(options => options.FocusSelection, ShowSelectedActors);
|
||||
|
||||
SetUpdate(ref _update, OnUpdate);
|
||||
@@ -267,6 +268,7 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private void OnCollectDrawCalls(ref RenderContext renderContext)
|
||||
{
|
||||
DragHandlers.CollectDrawCalls(_debugDrawData, ref renderContext);
|
||||
_debugDrawData.OnDraw(ref renderContext);
|
||||
}
|
||||
|
||||
@@ -306,6 +308,7 @@ namespace FlaxEditor.Viewport
|
||||
var orient = ViewOrientation;
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orient);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public EditorViewport Viewport => this;
|
||||
|
||||
@@ -354,6 +357,12 @@ namespace FlaxEditor.Viewport
|
||||
_window.Select(nodes);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Spawn(Actor actor)
|
||||
{
|
||||
_window.Spawn(actor);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
||||
|
||||
@@ -669,11 +678,11 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
|
||||
{
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragEnter(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
return _dragHandlers.OnDragEnter(data);
|
||||
return DragHandlers.DragEnter(ref location, data);
|
||||
}
|
||||
|
||||
private bool ValidateDragItem(ContentItem contentItem)
|
||||
@@ -685,7 +694,6 @@ namespace FlaxEditor.Viewport
|
||||
if (assetItem.IsOfType<MaterialBase>())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -697,86 +705,21 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragMove(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
return _dragHandlers.Effect;
|
||||
return DragHandlers.DragEnter(ref location, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_dragHandlers.OnDragLeave();
|
||||
|
||||
DragHandlers.ClearDragEffects();
|
||||
DragHandlers.OnDragLeave();
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
private Vector3 PostProcessSpawnedActorLocation(Actor actor, ref Vector3 hitLocation)
|
||||
{
|
||||
// Place the object
|
||||
//var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection;
|
||||
var location = hitLocation;
|
||||
|
||||
// Apply grid snapping if enabled
|
||||
if (UseSnapping || TransformGizmo.TranslationSnapEnable)
|
||||
{
|
||||
float snapValue = TransformGizmo.TranslationSnapValue;
|
||||
location = new Vector3(
|
||||
(int)(location.X / snapValue) * snapValue,
|
||||
(int)(location.Y / snapValue) * snapValue,
|
||||
(int)(location.Z / snapValue) * snapValue);
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
private void Spawn(AssetItem item, SceneGraphNode hit, ref Float2 location, ref Vector3 hitLocation)
|
||||
{
|
||||
if (item is BinaryAssetItem binaryAssetItem)
|
||||
{
|
||||
if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
if (hit is StaticModelNode staticModelNode)
|
||||
{
|
||||
var staticModel = (StaticModel)staticModelNode.Actor;
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
|
||||
{
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
|
||||
using (new UndoBlock(Undo, staticModel, "Change material"))
|
||||
staticModel.SetMaterial(entryIndex, material);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
{
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private void Spawn(Actor actor, ref Vector3 hitLocation)
|
||||
{
|
||||
actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation);
|
||||
_window.Spawn(actor);
|
||||
Focus();
|
||||
}
|
||||
|
||||
private void Spawn(ScriptType item, SceneGraphNode hit, ref Vector3 hitLocation)
|
||||
{
|
||||
var actor = item.CreateInstance() as Actor;
|
||||
if (actor == null)
|
||||
{
|
||||
Editor.LogWarning("Failed to spawn actor of type " + item.TypeName);
|
||||
return;
|
||||
}
|
||||
actor.Name = item.Name;
|
||||
Spawn(actor, ref hitLocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
@@ -814,57 +757,11 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
|
||||
{
|
||||
DragHandlers.ClearDragEffects();
|
||||
var result = base.OnDragDrop(ref location, data);
|
||||
if (result != DragDropEffect.None)
|
||||
return result;
|
||||
|
||||
// Check if drag sth
|
||||
Vector3 hitLocation = ViewPosition;
|
||||
SceneGraphNode hit = null;
|
||||
if (_dragHandlers.HasValidDrag)
|
||||
{
|
||||
// Get mouse ray and try to hit any object
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
var view = new Ray(ViewPosition, ViewDirection);
|
||||
hit = _window.Graph.Root.RayCast(ref ray, ref view, out var closest, SceneGraphNode.RayCastData.FlagTypes.SkipColliders);
|
||||
if (hit != null)
|
||||
{
|
||||
// Use hit location
|
||||
hitLocation = ray.Position + ray.Direction * closest;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use area in front of the viewport
|
||||
hitLocation = ViewPosition + ViewDirection * 100;
|
||||
}
|
||||
}
|
||||
|
||||
// Drag assets
|
||||
if (_dragAssets.HasValidDrag)
|
||||
{
|
||||
result = _dragAssets.Effect;
|
||||
|
||||
// Process items
|
||||
for (int i = 0; i < _dragAssets.Objects.Count; i++)
|
||||
{
|
||||
var item = _dragAssets.Objects[i];
|
||||
Spawn(item, hit, ref location, ref hitLocation);
|
||||
}
|
||||
}
|
||||
// Drag actor type
|
||||
else if (_dragActorType.HasValidDrag)
|
||||
{
|
||||
result = _dragActorType.Effect;
|
||||
|
||||
// Process items
|
||||
for (int i = 0; i < _dragActorType.Objects.Count; i++)
|
||||
{
|
||||
var item = _dragActorType.Objects[i];
|
||||
Spawn(item, hit, ref hitLocation);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return DragHandlers.DragDrop(ref location, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -7,6 +7,8 @@ using FlaxEngine.GUI;
|
||||
using FlaxEditor.Viewport.Widgets;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using Object = FlaxEngine.Object;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
|
||||
namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
@@ -49,6 +51,8 @@ namespace FlaxEditor.Viewport.Previews
|
||||
private Image _guiMaterialControl;
|
||||
private readonly MaterialBase[] _postFxMaterialsCache = new MaterialBase[1];
|
||||
private ContextMenu _modelWidgetButtonMenu;
|
||||
private AssetPicker _customModelPicker;
|
||||
private Model _customModel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the material asset to preview. It can be <see cref="FlaxEngine.Material"/> or <see cref="FlaxEngine.MaterialInstance"/>.
|
||||
@@ -74,15 +78,66 @@ namespace FlaxEditor.Viewport.Previews
|
||||
get => _selectedModelIndex;
|
||||
set
|
||||
{
|
||||
if (value == -1) // Using Custom Model
|
||||
return;
|
||||
if (value < 0 || value > Models.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
if (_customModelPicker != null)
|
||||
_customModelPicker.Validator.SelectedAsset = null;
|
||||
_selectedModelIndex = value;
|
||||
_previewModel.Model = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Primitives/" + Models[value]);
|
||||
_previewModel.Transform = Transforms[value];
|
||||
}
|
||||
}
|
||||
|
||||
// Used to automatically update which entry is checked.
|
||||
// TODO: Maybe a better system with predicate bool checks could be used?
|
||||
private void ResetModelContextMenu()
|
||||
{
|
||||
_modelWidgetButtonMenu.ItemsContainer.DisposeChildren();
|
||||
|
||||
// Fill out all models
|
||||
for (int i = 0; i < Models.Length; i++)
|
||||
{
|
||||
var index = i;
|
||||
var button = _modelWidgetButtonMenu.AddButton(Models[index]);
|
||||
button.ButtonClicked += _ => SelectedModelIndex = index;
|
||||
button.Checked = SelectedModelIndex == index && _customModel == null;
|
||||
button.Tag = index;
|
||||
}
|
||||
|
||||
_modelWidgetButtonMenu.AddSeparator();
|
||||
_customModelPicker = new AssetPicker(new ScriptType(typeof(Model)), Float2.Zero);
|
||||
|
||||
// Label button
|
||||
var customModelPickerLabel = _modelWidgetButtonMenu.AddButton("Custom Model:");
|
||||
customModelPickerLabel.CloseMenuOnClick = false;
|
||||
customModelPickerLabel.Checked = _customModel != null;
|
||||
|
||||
// Container button
|
||||
var customModelPickerButton = _modelWidgetButtonMenu.AddButton("");
|
||||
customModelPickerButton.Height = _customModelPicker.Height + 4;
|
||||
customModelPickerButton.CloseMenuOnClick = false;
|
||||
_customModelPicker.Parent = customModelPickerButton;
|
||||
_customModelPicker.Validator.SelectedAsset = _customModel;
|
||||
_customModelPicker.SelectedItemChanged += () =>
|
||||
{
|
||||
_customModel = _customModelPicker.Validator.SelectedAsset as Model;
|
||||
if (_customModelPicker.Validator.SelectedAsset == null)
|
||||
{
|
||||
SelectedModelIndex = 0;
|
||||
ResetModelContextMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
_previewModel.Model = _customModel;
|
||||
_previewModel.Transform = Transforms[0];
|
||||
SelectedModelIndex = -1;
|
||||
ResetModelContextMenu();
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MaterialPreview"/> class.
|
||||
/// </summary>
|
||||
@@ -107,17 +162,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
if (!control.Visible)
|
||||
return;
|
||||
_modelWidgetButtonMenu.ItemsContainer.DisposeChildren();
|
||||
|
||||
// Fill out all models
|
||||
for (int i = 0; i < Models.Length; i++)
|
||||
{
|
||||
var index = i;
|
||||
var button = _modelWidgetButtonMenu.AddButton(Models[index]);
|
||||
button.ButtonClicked += _ => SelectedModelIndex = index;
|
||||
button.Checked = SelectedModelIndex == index;
|
||||
button.Tag = index;
|
||||
}
|
||||
ResetModelContextMenu();
|
||||
};
|
||||
new ViewportWidgetButton("Model", SpriteHandle.Invalid, _modelWidgetButtonMenu)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user