Compare commits
524 Commits
1.7.6404
...
1.7.6407.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e34524a08 | |||
| dfd3bcdcb7 | |||
| 3f1d851f82 | |||
| ceb564a5e2 | |||
| 8a94e053a8 | |||
| bc2e130281 | |||
| 72f45afa45 | |||
| 51c36223e6 | |||
| ea744ab4ac | |||
| 9ea5ed79f8 | |||
| 59e2afd992 | |||
| aade14270e | |||
| d5a6083a55 | |||
| e448692eb9 | |||
| 7bcf78d0c0 | |||
| 9f460cd651 | |||
| b85ec46545 | |||
| 272a147c2e | |||
| 8418ca56e8 | |||
| 0dd7e86537 | |||
| 64e391df24 | |||
| c145042f52 | |||
| d8856ddaa7 | |||
| 4263f61e85 | |||
| fc8c29b982 | |||
| 4e0daab310 | |||
| 6d5d615894 | |||
| 2bef880e21 | |||
| f38245b834 | |||
| 639803480e | |||
| 84249b3b57 | |||
| d614232f8d | |||
| 074ad171ba | |||
| efebb29ac0 | |||
| c3dd05211b | |||
| b9c145b499 | |||
| c0ef2a1f58 | |||
| 141bec0259 | |||
| 9c4857a205 | |||
| ae5fa9619b | |||
| a5e072da31 | |||
| df8418da25 | |||
| d7b17ae0a6 | |||
| 60202a3add | |||
| 014c811903 | |||
| fe1a655654 | |||
| 190bafea28 | |||
| 51fc4c68cd | |||
| b87a7d16fb | |||
| 8a5a7851cf | |||
| a1e13cd2c8 | |||
| e0a085adfe | |||
| 1874382816 | |||
| 9454385683 | |||
| d26b9818d8 | |||
| b297b9f185 | |||
| 8aaa5710df | |||
| 778dd2d3f0 | |||
| ff195eeccb | |||
| a63abb534f | |||
| 2afdb5b978 | |||
| ea287e9fc5 | |||
| 14632ecb66 | |||
| 80b5e9d02a | |||
| 022c935eef | |||
| ad7d7f371e | |||
| 4725f51431 | |||
| 0bb1126f1b | |||
| 462eb9803f | |||
| b1d4d50d47 | |||
| 2ed79c9218 | |||
| 6dd72cdf32 | |||
| 865945806a | |||
| d974998528 | |||
| efad58370f | |||
| 51e92a49ad | |||
| 1195fe8507 | |||
| cbecd605e9 | |||
| 0bcbcdb912 | |||
| 0df00fd881 | |||
| fe19ffddd9 | |||
| 19dbd3c4e4 | |||
| 01b233af10 | |||
| c895e310cb | |||
| e508fb8cd0 | |||
| 2f50042523 | |||
| 4e54e945ef | |||
| 0cb064bfb3 | |||
| b8ce9e8c59 | |||
| df83491313 | |||
| b1cbaf7e13 | |||
| f3497a2a55 | |||
| 86fbf05b09 | |||
| c17ff3926a | |||
| 4707f98fab | |||
| a32effff1c | |||
| f346dbc9bf | |||
| f24b335c45 | |||
| 306dd43b18 | |||
| c3b6dd9884 | |||
| f7e9465ce8 | |||
| f9ad6e00c2 | |||
| 73a3e147ca | |||
| 59fe448987 | |||
| 629ebacd64 | |||
| a6a94d5f77 | |||
| 4a50111f9b | |||
| 91033a6468 | |||
| 73074b6e44 | |||
| e9285410e2 | |||
| 526edb83de | |||
| 7db0ae59bb | |||
| eb7d5e5df3 | |||
| 83ef9791d4 | |||
| 228239632a | |||
| 3749b35aba | |||
| d847dfda61 | |||
| cb92110976 | |||
| 74b77bfa4c | |||
| 32ced6e68a | |||
| 23a72f2ade | |||
| af4c662738 | |||
| af4a6b80a8 | |||
| 84e25a9e90 | |||
| 1eca03e50c | |||
| 0cd5627845 | |||
| 49c21082a1 | |||
| 96e64b2d0a | |||
| 19db8c04ad | |||
| a5ffde8863 | |||
| 9e593195c0 | |||
| 9dc3889631 | |||
| 3328c678c1 | |||
| 4f3c7a43ab | |||
| 727ff155c2 | |||
| 8faaaaaf54 | |||
| 7a7a43b897 | |||
| 63773f2ddf | |||
| 3f632b7d15 | |||
| bcbc1cd413 | |||
| 7886069783 | |||
| 4a3be5a743 | |||
| fdfca5156b | |||
| 38a0718b70 | |||
| 2285116bae | |||
| 5575917c4b | |||
| 63ddf53ad3 | |||
| 3e940c28df | |||
| f654d507e5 | |||
| d6dc1f9998 | |||
| 1843689a88 | |||
| 022a69aaf2 | |||
| a6caa9dbfa | |||
| 73d33e4af0 | |||
| c5c20c8e28 | |||
| 9bde0f9f9b | |||
| 7d15944381 | |||
| 58bfd1954e | |||
| f67c0d2ac0 | |||
| 9a712ba3cf | |||
| 3ab7d7fcc4 | |||
| 78d9262b05 | |||
| c8dd2c045c | |||
| a808bcdbf6 | |||
| 640e01262f | |||
| 6e92d3103c | |||
| c5df7ad689 | |||
| 712c400e43 | |||
| 7f87e9794b | |||
| cebd28c3a7 | |||
| eb508fdc73 | |||
| b7e4fe3e85 | |||
| c6017a21f3 | |||
| d3a77c7a55 | |||
| 8ff4f95cef | |||
| 4f8aff4352 | |||
| 0aeac36f09 | |||
| cf8b7a20c2 | |||
| 47b8c9978f | |||
| a909b57e82 | |||
| 35ebdb0ffe | |||
| fd938e8284 | |||
| 17dca8c5c7 | |||
| 8ffc86ef88 | |||
| a3f1dc2694 | |||
| 84f3d50925 | |||
| a06a079804 | |||
| 475453aa60 | |||
| 39dc5939e3 | |||
| 437819bfce | |||
| fa972a3c77 | |||
| 926297a63f | |||
| fd76c63a24 | |||
| 2f4b956d78 | |||
| c577c78f3f | |||
| ef8bb33105 | |||
| aab88a746d | |||
| 0bcd0154e1 | |||
| e5b1a10d34 | |||
| b3a18883ca | |||
| 98b42d3e2e | |||
| 71f30f18a6 | |||
| 9e74f3ae22 | |||
| f4f49f63bc | |||
| eaabd56cae | |||
| 3fc0a3dc84 | |||
| cf155a4df4 | |||
| 40d6e18e7e | |||
| 2cef368282 | |||
| 40d8d3b972 | |||
| 2ddef2c6be | |||
| 6eb738bc58 | |||
| 91629d7a28 | |||
| cfef59d851 | |||
| 5f3fc38de2 | |||
| 49bc7d3dcc | |||
| d0f7a04c58 | |||
| 53aae90d45 | |||
| 297cdc5bfd | |||
| f61f35b259 | |||
| aa1b779463 | |||
| 359d4ba8ef | |||
| 6cf7d49a10 | |||
| d5075d845c | |||
| d99a92fd13 | |||
| 5b7a3f9700 | |||
| 94f1dff497 | |||
| fe53317ec7 | |||
| 317886e893 | |||
| 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.
BIN
Binary file not shown.
+2
-2
@@ -3,8 +3,8 @@
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 7,
|
||||
"Revision": 0,
|
||||
"Build": 6404
|
||||
"Revision": 2,
|
||||
"Build": 6407
|
||||
},
|
||||
"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;
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,14 @@ namespace FlaxEngine.Tools
|
||||
{
|
||||
partial struct Options
|
||||
{
|
||||
private bool ShowGeometry => Type == ModelTool.ModelType.Model || Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowModel => Type == ModelTool.ModelType.Model;
|
||||
private bool ShowSkinnedModel => Type == ModelTool.ModelType.SkinnedModel;
|
||||
private bool ShowAnimation => Type == ModelTool.ModelType.Animation;
|
||||
private bool ShowGeometry => Type == ModelType.Model || Type == ModelType.SkinnedModel || Type == ModelType.Prefab;
|
||||
private bool ShowModel => Type == ModelType.Model || Type == ModelType.Prefab;
|
||||
private bool ShowSkinnedModel => Type == ModelType.SkinnedModel || Type == ModelType.Prefab;
|
||||
private bool ShowAnimation => Type == ModelType.Animation || Type == ModelType.Prefab;
|
||||
private bool ShowSmoothingNormalsAngle => ShowGeometry && CalculateNormals;
|
||||
private bool ShowSmoothingTangentsAngle => ShowGeometry && CalculateTangents;
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == ModelTool.AnimationDuration.Custom;
|
||||
private bool ShowFramesRange => ShowAnimation && Duration == AnimationDuration.Custom;
|
||||
private bool ShowSplitting => Type != ModelType.Prefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
||||
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
|
||||
@@ -92,15 +93,12 @@ SpriteHandle PreviewsCache::FindSlot(const Guid& id)
|
||||
{
|
||||
if (WaitForLoaded())
|
||||
return SpriteHandle::Invalid;
|
||||
|
||||
// Find entry
|
||||
int32 index;
|
||||
if (_assets.Find(id, index))
|
||||
{
|
||||
const String spriteName = StringUtils::ToString(index);
|
||||
return FindSprite(spriteName);
|
||||
}
|
||||
|
||||
return SpriteHandle::Invalid;
|
||||
}
|
||||
|
||||
@@ -114,6 +112,17 @@ Asset::LoadResult PreviewsCache::load()
|
||||
return LoadResult::Failed;
|
||||
_assets.Set(previewsMetaChunk->Get<Guid>(), ASSETS_ICONS_PER_ATLAS);
|
||||
|
||||
// Verify if cached assets still exist (don't store thumbnails for removed files)
|
||||
AssetInfo assetInfo;
|
||||
for (Guid& id : _assets)
|
||||
{
|
||||
if (id.IsValid() && Content::GetAsset(id) == nullptr && !Content::GetAssetInfo(id, assetInfo))
|
||||
{
|
||||
// Free slot (no matter the texture contents)
|
||||
id = Guid::Empty;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup atlas sprites array
|
||||
Sprite sprite;
|
||||
sprite.Area.Size = static_cast<float>(ASSET_ICON_SIZE) / ASSETS_ICONS_ATLAS_SIZE;
|
||||
@@ -162,7 +171,7 @@ SpriteHandle PreviewsCache::OccupySlot(GPUTexture* source, const Guid& id)
|
||||
if (WaitForLoaded())
|
||||
return SpriteHandle::Invalid;
|
||||
|
||||
// Find free slot and for that asset
|
||||
// Find this asset slot or use the first empty
|
||||
int32 index = _assets.Find(id);
|
||||
if (index == INVALID_INDEX)
|
||||
index = _assets.Find(Guid::Empty);
|
||||
@@ -201,14 +210,12 @@ bool PreviewsCache::ReleaseSlot(const Guid& id)
|
||||
{
|
||||
bool result = false;
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
int32 index = _assets.Find(id);
|
||||
if (index != INVALID_INDEX)
|
||||
{
|
||||
_assets[index] = Guid::Empty;
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
if (_preview == null)
|
||||
{
|
||||
_preview = new ModelPreview(false);
|
||||
_preview = new ModelPreview(false)
|
||||
{
|
||||
ScaleToFit = false,
|
||||
};
|
||||
InitAssetPreview(_preview);
|
||||
}
|
||||
|
||||
@@ -91,6 +94,7 @@ namespace FlaxEditor.Content
|
||||
_preview.Model = (Model)request.Asset;
|
||||
_preview.Parent = guiRoot;
|
||||
_preview.SyncBackbufferSize();
|
||||
_preview.ViewportCamera.SetArcBallView(_preview.Model.GetBox());
|
||||
|
||||
_preview.Task.OnDraw();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -68,5 +69,15 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
return new SceneItem(path, id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnContentWindowContextMenu(ContextMenu menu, ContentItem item)
|
||||
{
|
||||
var id = ((SceneItem)item).ID;
|
||||
if (Level.FindScene(id) == null)
|
||||
{
|
||||
menu.AddButton("Open (additive)", () => { Editor.Instance.Scene.OpenScene(id, true); });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
/// The finalized state.
|
||||
/// </summary>
|
||||
Disposed,
|
||||
|
||||
/// <summary>
|
||||
/// The request has failed (eg. asset cannot be loaded).
|
||||
/// </summary>
|
||||
Failed,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -78,6 +83,14 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
Proxy = proxy;
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (State == States.Prepared && (!Asset || Asset.LastLoadFailed))
|
||||
{
|
||||
State = States.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares this request.
|
||||
/// </summary>
|
||||
@@ -85,11 +98,8 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
{
|
||||
if (State != States.Created)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
// Prepare
|
||||
Asset = FlaxEngine.Content.LoadAsync(Item.Path);
|
||||
Proxy.OnThumbnailDrawPrepare(this);
|
||||
|
||||
State = States.Prepared;
|
||||
}
|
||||
|
||||
@@ -101,9 +111,7 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
{
|
||||
if (State != States.Prepared)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Item.Thumbnail = icon;
|
||||
|
||||
State = States.Rendered;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,15 +21,11 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
/// </summary>
|
||||
public const float MinimumRequiredResourcesQuality = 0.8f;
|
||||
|
||||
// TODO: free atlas slots for deleted assets
|
||||
|
||||
private readonly List<PreviewsCache> _cache = new List<PreviewsCache>(4);
|
||||
private readonly string _cacheFolder;
|
||||
|
||||
private DateTime _lastFlushTime;
|
||||
|
||||
private readonly List<ThumbnailRequest> _requests = new List<ThumbnailRequest>(128);
|
||||
private readonly PreviewRoot _guiRoot = new PreviewRoot();
|
||||
private DateTime _lastFlushTime;
|
||||
private RenderTask _task;
|
||||
private GPUTexture _output;
|
||||
|
||||
@@ -88,7 +84,6 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
}
|
||||
}
|
||||
|
||||
// Add request
|
||||
AddRequest(assetItem, proxy);
|
||||
}
|
||||
}
|
||||
@@ -118,15 +113,15 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
for (int i = 0; i < _cache.Count; i++)
|
||||
{
|
||||
if (_cache[i].ReleaseSlot(assetItem.ID))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool HasMinimumQuality(TextureBase asset)
|
||||
{
|
||||
if (asset.HasStreamingError)
|
||||
return true; // Don't block thumbnails queue when texture fails to stream in (eg. unsupported format)
|
||||
var mipLevels = asset.MipLevels;
|
||||
var minMipLevels = Mathf.Min(mipLevels, 7);
|
||||
return asset.IsLoaded && asset.ResidentMipLevels >= Mathf.Max(minMipLevels, (int)(mipLevels * MinimumRequiredResourcesQuality));
|
||||
@@ -198,13 +193,7 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
/// <inheritdoc />
|
||||
void IContentItemOwner.OnItemDeleted(ContentItem item)
|
||||
{
|
||||
if (item is AssetItem assetItem)
|
||||
{
|
||||
lock (_requests)
|
||||
{
|
||||
RemoveRequest(assetItem);
|
||||
}
|
||||
}
|
||||
DeletePreview(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -494,10 +483,7 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
{
|
||||
// Wait some frames before start generating previews (late init feature)
|
||||
if (Time.TimeSinceStartup < 1.0f || HasAllAtlasesLoaded() == false)
|
||||
{
|
||||
// Back
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_requests)
|
||||
{
|
||||
@@ -515,6 +501,7 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
var request = _requests[i];
|
||||
try
|
||||
{
|
||||
request.Update();
|
||||
if (request.IsReady)
|
||||
{
|
||||
isAnyReady = true;
|
||||
@@ -523,6 +510,10 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
{
|
||||
request.Prepare();
|
||||
}
|
||||
else if (request.State == ThumbnailRequest.States.Failed)
|
||||
{
|
||||
_requests.RemoveAt(i--);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,16 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
protected ContentFolder _folder;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this node can be deleted.
|
||||
/// </summary>
|
||||
public virtual bool CanDelete => true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this node can be duplicated.
|
||||
/// </summary>
|
||||
public virtual bool CanDuplicate => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content folder item.
|
||||
/// </summary>
|
||||
@@ -86,6 +96,7 @@ namespace FlaxEditor.Content
|
||||
Folder.ParentFolder = parent.Folder;
|
||||
Parent = parent;
|
||||
}
|
||||
IconColor = Style.Current.Foreground;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -300,7 +311,7 @@ namespace FlaxEditor.Content
|
||||
StartRenaming();
|
||||
return true;
|
||||
case KeyboardKeys.Delete:
|
||||
if (Folder.Exists)
|
||||
if (Folder.Exists && CanDelete)
|
||||
Editor.Instance.Windows.ContentWin.Delete(Folder);
|
||||
return true;
|
||||
}
|
||||
@@ -309,7 +320,7 @@ namespace FlaxEditor.Content
|
||||
switch (key)
|
||||
{
|
||||
case KeyboardKeys.D:
|
||||
if (Folder.Exists)
|
||||
if (Folder.Exists && CanDuplicate)
|
||||
Editor.Instance.Windows.ContentWin.Duplicate(Folder);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,12 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
private FileSystemWatcher _watcher;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanDelete => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanDuplicate => false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MainContentTreeNode"/> class.
|
||||
/// </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>
|
||||
|
||||
@@ -169,6 +169,30 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
permissions += String::Format(TEXT("\n <uses-permission android:name=\"{0}\" />"), e.Item);
|
||||
}
|
||||
|
||||
// Setup default Android screen orientation
|
||||
auto defaultOrienation = platformSettings->DefaultOrientation;
|
||||
String orientation = String("fullSensor");
|
||||
switch (defaultOrienation)
|
||||
{
|
||||
case AndroidPlatformSettings::ScreenOrientation::Portrait:
|
||||
orientation = String("portrait");
|
||||
break;
|
||||
case AndroidPlatformSettings::ScreenOrientation::PortraitReverse:
|
||||
orientation = String("reversePortrait");
|
||||
break;
|
||||
case AndroidPlatformSettings::ScreenOrientation::LandscapeRight:
|
||||
orientation = String("landscape");
|
||||
break;
|
||||
case AndroidPlatformSettings::ScreenOrientation::LandscapeLeft:
|
||||
orientation = String("reverseLandscape");
|
||||
break;
|
||||
case AndroidPlatformSettings::ScreenOrientation::AutoRotation:
|
||||
orientation = String("fullSensor");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup Android application attributes
|
||||
String attributes;
|
||||
if (data.Configuration != BuildConfiguration::Release)
|
||||
@@ -223,6 +247,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
EditorUtilities::ReplaceInFile(manifestPath, TEXT("${PackageName}"), packageName);
|
||||
EditorUtilities::ReplaceInFile(manifestPath, TEXT("${ProjectVersion}"), projectVersion);
|
||||
EditorUtilities::ReplaceInFile(manifestPath, TEXT("${AndroidPermissions}"), permissions);
|
||||
EditorUtilities::ReplaceInFile(manifestPath, TEXT("${DefaultOrientation}"), orientation);
|
||||
EditorUtilities::ReplaceInFile(manifestPath, TEXT("${AndroidAttributes}"), attributes);
|
||||
const String stringsPath = data.OriginalOutputPath / TEXT("app/src/main/res/values/strings.xml");
|
||||
EditorUtilities::ReplaceInFile(stringsPath, TEXT("${ProjectName}"), gameSettings->ProductName);
|
||||
@@ -280,17 +305,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
|
||||
|
||||
@@ -1270,7 +1270,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
Array<CookingData::AssetTypeStatistics> assetTypes;
|
||||
data.Stats.AssetStats.GetValues(assetTypes);
|
||||
Sorting::QuickSort(assetTypes.Get(), assetTypes.Count());
|
||||
Sorting::QuickSort(assetTypes);
|
||||
|
||||
LOG(Info, "");
|
||||
LOG(Info, "Top assets types stats:");
|
||||
|
||||
@@ -48,21 +48,21 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (buildSettings.SkipDotnetPackaging && data.Tools->UseSystemDotnet())
|
||||
{
|
||||
// Use system-installed .Net Runtime
|
||||
// Use system-installed .NET Runtime
|
||||
FileSystem::DeleteDirectory(dstDotnet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Deploy .Net Runtime files
|
||||
// Deploy .NET Runtime files
|
||||
FileSystem::CreateDirectory(dstDotnet);
|
||||
String srcDotnet = depsRoot / TEXT("Dotnet");
|
||||
if (FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
// Use prebuilt .Net installation for that platform
|
||||
LOG(Info, "Using .Net Runtime {} at {}", data.Tools->GetName(), srcDotnet);
|
||||
// Use prebuilt .NET installation for that platform
|
||||
LOG(Info, "Using .NET Runtime {} at {}", data.Tools->GetName(), srcDotnet);
|
||||
if (EditorUtilities::CopyDirectoryIfNewer(dstDotnet, srcDotnet, true))
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
data.Error(TEXT("Failed to copy .NET runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -85,9 +85,9 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (canUseSystemDotnet && (aotMode == DotNetAOTModes::None || aotMode == DotNetAOTModes::ILC))
|
||||
{
|
||||
// Ask Flax.Build to provide .Net SDK location for the current platform
|
||||
// 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)
|
||||
@@ -101,7 +101,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
data.Error(TEXT("Failed to get .NET SDK location for the current host platform."));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,19 +110,25 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
FileSystem::GetChildDirectories(versions, srcDotnet / TEXT("host/fxr"));
|
||||
if (versions.Count() == 0)
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
data.Error(TEXT("Failed to find any .NET hostfxr versions for the current host platform."));
|
||||
return true;
|
||||
}
|
||||
for (String& version : versions)
|
||||
{
|
||||
version = String(StringUtils::GetFileName(version));
|
||||
if (!version.StartsWith(TEXT("7.")))
|
||||
if (!version.StartsWith(TEXT("7.")) && !version.StartsWith(TEXT("8."))) // .NET 7 or .NET 8
|
||||
version.Clear();
|
||||
}
|
||||
Sorting::QuickSort(versions.Get(), versions.Count());
|
||||
Sorting::QuickSort(versions);
|
||||
const String version = versions.Last();
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
data.Error(TEXT("Failed to find supported .NET hostfxr version for the current host platform."));
|
||||
return true;
|
||||
}
|
||||
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", version, srcDotnet);
|
||||
LOG(Info, "Using .NET Runtime {} at {}", version, srcDotnet);
|
||||
|
||||
// Check if previously deployed files are valid (eg. system-installed .NET was updated from version 7.0.3 to 7.0.5)
|
||||
{
|
||||
@@ -158,17 +164,17 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
data.Error(TEXT("Failed to copy .NET runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ask Flax.Build to provide .Net Host Runtime location for the target platform
|
||||
// Ask Flax.Build to provide .NET Host Runtime location for the target platform
|
||||
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;
|
||||
@@ -180,11 +186,11 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (failed || !FileSystem::DirectoryExists(srcDotnet))
|
||||
{
|
||||
data.Error(TEXT("Failed to get .Net SDK location for a current platform."));
|
||||
data.Error(TEXT("Failed to get .NET SDK location for the current host platform."));
|
||||
return true;
|
||||
}
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .Net Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||
LOG(Info, "Using .NET Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||
|
||||
// Deploy runtime files
|
||||
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
||||
@@ -249,7 +255,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Net.Security.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.NET.Security.Native.dylib");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Apple.dylib");
|
||||
break;
|
||||
#undef DEPLOY_NATIVE_FILE
|
||||
@@ -257,7 +263,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (failed)
|
||||
{
|
||||
data.Error(TEXT("Failed to copy .Net runtime data files."));
|
||||
data.Error(TEXT("Failed to copy .NET runtime data files."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -269,8 +275,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");
|
||||
@@ -278,7 +284,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (ScriptsBuilder::RunBuildTool(args))
|
||||
{
|
||||
data.Error(TEXT("Failed to optimize .Net class library."));
|
||||
data.Error(TEXT("Failed to optimize .NET class library."));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -7,9 +7,8 @@ using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
using JsonSerializer = FlaxEngine.Json.JsonSerializer;
|
||||
|
||||
namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
@@ -157,6 +156,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;
|
||||
@@ -380,22 +385,22 @@ namespace FlaxEditor.CustomEditors
|
||||
LinkedLabel = label;
|
||||
}
|
||||
|
||||
private void RevertDiffToDefault(CustomEditor editor)
|
||||
{
|
||||
if (editor.ChildrenEditors.Count == 0)
|
||||
{
|
||||
// Skip if no change detected
|
||||
if (!editor.Values.IsDefaultValueModified)
|
||||
return;
|
||||
/// <summary>
|
||||
/// If true, the value reverting to default/reference will be handled via iteration over children editors, instead of for a whole object at once.
|
||||
/// </summary>
|
||||
public virtual bool RevertValueWithChildren => ChildrenEditors.Count != 0;
|
||||
|
||||
editor.SetValueToDefault();
|
||||
private void RevertDiffToDefault()
|
||||
{
|
||||
if (RevertValueWithChildren)
|
||||
{
|
||||
foreach (var child in ChildrenEditors)
|
||||
child.RevertDiffToDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < editor.ChildrenEditors.Count; i++)
|
||||
{
|
||||
RevertDiffToDefault(editor.ChildrenEditors[i]);
|
||||
}
|
||||
if (Values.IsDefaultValueModified)
|
||||
SetValueToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,11 +413,6 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (!Values.IsDefaultValueModified)
|
||||
return false;
|
||||
|
||||
// Skip array items (show diff only on a bottom level properties and fields)
|
||||
if (ParentEditor is Editors.ArrayEditor)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -424,7 +424,7 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (!Values.HasDefaultValue)
|
||||
return;
|
||||
RevertDiffToDefault(this);
|
||||
RevertDiffToDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -462,22 +462,17 @@ namespace FlaxEditor.CustomEditors
|
||||
}
|
||||
}
|
||||
|
||||
private void RevertDiffToReference(CustomEditor editor)
|
||||
private void RevertDiffToReference()
|
||||
{
|
||||
if (editor.ChildrenEditors.Count == 0)
|
||||
if (RevertValueWithChildren)
|
||||
{
|
||||
// Skip if no change detected
|
||||
if (!editor.Values.IsReferenceValueModified)
|
||||
return;
|
||||
|
||||
editor.SetValueToReference();
|
||||
foreach (var child in ChildrenEditors)
|
||||
child.RevertDiffToReference();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < editor.ChildrenEditors.Count; i++)
|
||||
{
|
||||
RevertDiffToReference(editor.ChildrenEditors[i]);
|
||||
}
|
||||
if (Values.IsReferenceValueModified)
|
||||
SetValueToReference();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,11 +485,6 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (!Values.IsReferenceValueModified)
|
||||
return false;
|
||||
|
||||
// Skip array items (show diff only on a bottom level properties and fields)
|
||||
if (ParentEditor is Editors.ArrayEditor)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -506,7 +496,7 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (!Values.HasReferenceValue)
|
||||
return;
|
||||
RevertDiffToReference(this);
|
||||
RevertDiffToReference();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -651,7 +641,7 @@ namespace FlaxEditor.CustomEditors
|
||||
// Default
|
||||
try
|
||||
{
|
||||
obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
obj = Newtonsoft.Json.JsonConvert.DeserializeObject(text, TypeUtils.GetType(Values.Type), JsonSerializer.Settings);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -756,7 +746,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
public void SetValueToDefault()
|
||||
{
|
||||
SetValue(Values.DefaultValue);
|
||||
SetValueCloned(Values.DefaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -793,7 +783,19 @@ namespace FlaxEditor.CustomEditors
|
||||
return;
|
||||
}
|
||||
|
||||
SetValue(Values.ReferenceValue);
|
||||
SetValueCloned(Values.ReferenceValue);
|
||||
}
|
||||
|
||||
private void SetValueCloned(object value)
|
||||
{
|
||||
// For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor
|
||||
if (value != null && !value.GetType().IsValueType)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(value);
|
||||
value = JsonSerializer.Deserialize(json, value.GetType());
|
||||
}
|
||||
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -805,7 +807,6 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (_isSetBlocked)
|
||||
return;
|
||||
|
||||
if (OnDirty(this, value, token))
|
||||
{
|
||||
_hasValueDirty = true;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated;
|
||||
|
||||
/// <summary>
|
||||
/// The missing script editor.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(ModelPrefab)), DefaultEditor]
|
||||
public class ModelPrefabEditor : GenericEditor
|
||||
{
|
||||
private Guid _prefabId;
|
||||
private Button _reimportButton;
|
||||
private string _importPath;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
var modelPrefab = Values[0] as ModelPrefab;
|
||||
if (modelPrefab == null)
|
||||
return;
|
||||
_prefabId = modelPrefab.PrefabID;
|
||||
while (true)
|
||||
{
|
||||
if (_prefabId == Guid.Empty)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var prefab = FlaxEngine.Content.Load<Prefab>(_prefabId);
|
||||
if (prefab)
|
||||
{
|
||||
var prefabObjectId = modelPrefab.PrefabObjectID;
|
||||
var prefabObject = prefab.GetDefaultInstance(ref prefabObjectId);
|
||||
if (prefabObject.PrefabID == _prefabId)
|
||||
break;
|
||||
_prefabId = prefabObject.PrefabID;
|
||||
}
|
||||
}
|
||||
|
||||
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
|
||||
_reimportButton = button.Button;
|
||||
_reimportButton.Clicked += OnReimport;
|
||||
}
|
||||
|
||||
private void OnReimport()
|
||||
{
|
||||
var prefab = FlaxEngine.Content.Load<Prefab>(_prefabId);
|
||||
var modelPrefab = (ModelPrefab)Values[0];
|
||||
var importPath = modelPrefab.ImportPath;
|
||||
var editor = Editor.Instance;
|
||||
if (editor.ContentImporting.GetReimportPath("Model Prefab", ref importPath))
|
||||
return;
|
||||
var folder = editor.ContentDatabase.Find(Path.GetDirectoryName(prefab.Path)) as ContentFolder;
|
||||
if (folder == null)
|
||||
return;
|
||||
var importOptions = modelPrefab.ImportOptions;
|
||||
importOptions.Type = ModelTool.ModelType.Prefab;
|
||||
_importPath = importPath;
|
||||
_reimportButton.Enabled = false;
|
||||
editor.ContentImporting.ImportFileEnd += OnImportFileEnd;
|
||||
editor.ContentImporting.Import(importPath, folder, true, importOptions);
|
||||
}
|
||||
|
||||
private void OnImportFileEnd(IFileEntryAction entry, bool failed)
|
||||
{
|
||||
if (entry.SourceUrl == _importPath)
|
||||
{
|
||||
// Restore button
|
||||
_importPath = null;
|
||||
_reimportButton.Enabled = true;
|
||||
Editor.Instance.ContentImporting.ImportFileEnd -= OnImportFileEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,6 +246,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var multiAction = new MultiUndoAction(actions);
|
||||
multiAction.Do();
|
||||
var presenter = ScriptsEditor.Presenter;
|
||||
ScriptsEditor.ParentEditor?.RebuildLayout();
|
||||
if (presenter != null)
|
||||
{
|
||||
presenter.Undo.AddAction(multiAction);
|
||||
|
||||
@@ -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;
|
||||
@@ -84,6 +87,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
protected bool NotNullItems;
|
||||
|
||||
private IntegerValueElement _size;
|
||||
private PropertyNameLabel _sizeLabel;
|
||||
private Color _background;
|
||||
private int _elementsCount;
|
||||
private bool _readOnly;
|
||||
@@ -106,11 +110,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool RevertValueWithChildren => false; // Always revert value for a whole collection
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
// No support for different collections for now
|
||||
if (HasDifferentValues || HasDifferentTypes)
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
|
||||
var size = Count;
|
||||
@@ -135,14 +142,45 @@ 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");
|
||||
var sizeProperty = dragArea.AddPropertyItem("Size");
|
||||
_sizeLabel = sizeProperty.Labels.Last();
|
||||
_size = sizeProperty.IntegerValue();
|
||||
_size.IntValue.MinValue = 0;
|
||||
_size.IntValue.MaxValue = ushort.MaxValue;
|
||||
_size.IntValue.Value = size;
|
||||
@@ -152,7 +190,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,40 +250,45 @@ 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_size = null;
|
||||
_sizeLabel = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the parent layout if its collection.
|
||||
/// </summary>
|
||||
@@ -268,7 +311,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
Resize(_size.IntValue.Value);
|
||||
}
|
||||
|
||||
@@ -283,11 +325,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return;
|
||||
|
||||
var cloned = CloneValues();
|
||||
|
||||
var tmp = cloned[dstIndex];
|
||||
cloned[dstIndex] = cloned[srcIndex];
|
||||
cloned[srcIndex] = tmp;
|
||||
|
||||
SetValue(cloned);
|
||||
}
|
||||
|
||||
@@ -343,6 +383,17 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (HasDifferentValues || HasDifferentTypes)
|
||||
return;
|
||||
|
||||
// Update reference/default value indicator
|
||||
if (_sizeLabel != null)
|
||||
{
|
||||
var color = Color.Transparent;
|
||||
if (Values.HasReferenceValue && Values.ReferenceValue is IList referenceValue && referenceValue.Count != Count)
|
||||
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
|
||||
else if (Values.HasDefaultValue && Values.DefaultValue is IList defaultValue && defaultValue.Count != Count)
|
||||
color = Color.Yellow * 0.8f;
|
||||
_sizeLabel.HighlightStripColor = color;
|
||||
}
|
||||
|
||||
// Check if collection has been resized (by UI or from external source)
|
||||
if (Count != _elementsCount)
|
||||
{
|
||||
@@ -369,5 +420,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)
|
||||
|
||||
@@ -73,7 +73,6 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
if (instanceValues == null || instanceValues.Count != Count)
|
||||
throw new ArgumentException();
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
var v = instanceValues[i];
|
||||
|
||||
@@ -404,13 +404,23 @@ int32 Editor::LoadProduct()
|
||||
|
||||
// Create new project option
|
||||
if (CommandLine::Options.NewProject)
|
||||
{
|
||||
Array<String> projectFiles;
|
||||
FileSystem::DirectoryGetFiles(projectFiles, projectPath, TEXT("*.flaxproj"), DirectorySearchOption::TopDirectoryOnly);
|
||||
if (projectFiles.Count() == 1)
|
||||
{
|
||||
// Skip creating new project if it already exists
|
||||
LOG(Info, "Skip creatinng new project because it already exists");
|
||||
CommandLine::Options.NewProject.Reset();
|
||||
}
|
||||
}
|
||||
if (CommandLine::Options.NewProject)
|
||||
{
|
||||
if (projectPath.IsEmpty())
|
||||
projectPath = Platform::GetWorkingDirectory();
|
||||
else if (!FileSystem::DirectoryExists(projectPath))
|
||||
FileSystem::CreateDirectory(projectPath);
|
||||
FileSystem::NormalizePath(projectPath);
|
||||
|
||||
String folderName = StringUtils::GetFileName(projectPath);
|
||||
String tmpName;
|
||||
for (int32 i = 0; i < folderName.Length(); i++)
|
||||
|
||||
@@ -1343,108 +1343,6 @@ namespace FlaxEditor
|
||||
public float AutoRebuildNavMeshTimeoutMs;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptLocalMarshaller))]
|
||||
internal struct VisualScriptLocal
|
||||
{
|
||||
public string Value;
|
||||
public string ValueTypeName;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptLocal), MarshalMode.Default, typeof(VisualScriptLocalMarshaller))]
|
||||
internal static class VisualScriptLocalMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptLocalNative
|
||||
{
|
||||
public IntPtr Value;
|
||||
public IntPtr ValueTypeName;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptLocal ConvertToManaged(VisualScriptLocalNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptLocalNative ConvertToUnmanaged(VisualScriptLocal managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptLocal ToManaged(VisualScriptLocalNative managed)
|
||||
{
|
||||
return new VisualScriptLocal()
|
||||
{
|
||||
Value = ManagedString.ToManaged(managed.Value),
|
||||
ValueTypeName = ManagedString.ToManaged(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static VisualScriptLocalNative ToNative(VisualScriptLocal managed)
|
||||
{
|
||||
return new VisualScriptLocalNative()
|
||||
{
|
||||
Value = ManagedString.ToNative(managed.Value),
|
||||
ValueTypeName = ManagedString.ToNative(managed.ValueTypeName),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static void Free(VisualScriptLocalNative unmanaged)
|
||||
{
|
||||
ManagedString.Free(unmanaged.Value);
|
||||
ManagedString.Free(unmanaged.ValueTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[NativeMarshalling(typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal struct VisualScriptStackFrame
|
||||
{
|
||||
public VisualScript Script;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
[CustomMarshaller(typeof(VisualScriptStackFrame), MarshalMode.Default, typeof(VisualScriptStackFrameMarshaller))]
|
||||
internal static class VisualScriptStackFrameMarshaller
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct VisualScriptStackFrameNative
|
||||
{
|
||||
public IntPtr Script;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
internal static VisualScriptStackFrame ConvertToManaged(VisualScriptStackFrameNative unmanaged) => ToManaged(unmanaged);
|
||||
internal static VisualScriptStackFrameNative ConvertToUnmanaged(VisualScriptStackFrame managed) => ToNative(managed);
|
||||
|
||||
internal static VisualScriptStackFrame ToManaged(VisualScriptStackFrameNative managed)
|
||||
{
|
||||
return new VisualScriptStackFrame()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToManaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static VisualScriptStackFrameNative ToNative(VisualScriptStackFrame managed)
|
||||
{
|
||||
return new VisualScriptStackFrameNative()
|
||||
{
|
||||
Script = VisualScriptMarshaller.ConvertToUnmanaged(managed.Script),
|
||||
NodeId = managed.NodeId,
|
||||
BoxId = managed.BoxId,
|
||||
};
|
||||
}
|
||||
|
||||
internal static void Free(VisualScriptStackFrameNative unmanaged)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal void BuildCommand(string arg)
|
||||
{
|
||||
if (TryBuildCommand(arg))
|
||||
@@ -1723,21 +1621,6 @@ namespace FlaxEditor
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptLocals", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "localsCount")]
|
||||
internal static partial VisualScriptLocal[] Internal_GetVisualScriptLocals(out int localsCount);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptStackFrames", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "stackFrameCount")]
|
||||
internal static partial VisualScriptStackFrame[] Internal_GetVisualScriptStackFrames(out int stackFrameCount);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetVisualScriptPreviousScopeFrame", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial VisualScriptStackFrame Internal_GetVisualScriptPreviousScopeFrame();
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_EvaluateVisualScriptLocal", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_EvaluateVisualScriptLocal(IntPtr script, ref VisualScriptLocal local);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
@@ -30,6 +32,8 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
private const float HSVMargin = 0.0f;
|
||||
private const float ChannelsMargin = 4.0f;
|
||||
private const float ChannelTextWidth = 12.0f;
|
||||
private const float SavedColorButtonWidth = 20.0f;
|
||||
private const float SavedColorButtonHeight = 20.0f;
|
||||
|
||||
private Color _initialValue;
|
||||
private Color _value;
|
||||
@@ -52,6 +56,9 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
private Button _cOK;
|
||||
private Button _cEyedropper;
|
||||
|
||||
private List<Color> _savedColors = new List<Color>();
|
||||
private List<Button> _savedColorButtons = new List<Button>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected color.
|
||||
/// </summary>
|
||||
@@ -111,6 +118,12 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
_onChanged = colorChanged;
|
||||
_onClosed = pickerClosed;
|
||||
|
||||
// Get saved colors if they exist
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out var savedColors))
|
||||
{
|
||||
_savedColors = JsonSerializer.Deserialize<List<Color>>(savedColors);
|
||||
}
|
||||
|
||||
// Selector
|
||||
_cSelector = new ColorSelectorWithSliders(180, 18)
|
||||
{
|
||||
@@ -195,6 +208,9 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
};
|
||||
_cOK.Clicked += OnSubmit;
|
||||
|
||||
// Create saved color buttons
|
||||
CreateAllSaveButtons();
|
||||
|
||||
// Eyedropper button
|
||||
var style = Style.Current;
|
||||
_cEyedropper = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin)
|
||||
@@ -216,6 +232,50 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
SelectedColor = initialValue;
|
||||
}
|
||||
|
||||
private void OnSavedColorButtonClicked(Button button)
|
||||
{
|
||||
if (button.Tag == null)
|
||||
{
|
||||
// Prevent setting same color 2 times... because why...
|
||||
foreach (var color in _savedColors)
|
||||
{
|
||||
if (color == _value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set color of button to current value;
|
||||
button.BackgroundColor = _value;
|
||||
button.BackgroundColorHighlighted = _value;
|
||||
button.BackgroundColorSelected = _value.RGBMultiplied(0.8f);
|
||||
button.Text = "";
|
||||
button.Tag = _value;
|
||||
|
||||
// Save new colors
|
||||
_savedColors.Add(_value);
|
||||
var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>));
|
||||
Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors);
|
||||
|
||||
// create new + button
|
||||
if (_savedColorButtons.Count < 8)
|
||||
{
|
||||
var savedColorButton = new Button(PickerMargin * (_savedColorButtons.Count + 1) + SavedColorButtonWidth * _savedColorButtons.Count, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
|
||||
{
|
||||
Text = "+",
|
||||
Parent = this,
|
||||
Tag = null,
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
_savedColorButtons.Add(savedColorButton);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedColor = (Color)button.Tag;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnColorPicked(Color32 colorPicked)
|
||||
{
|
||||
if (_activeEyedropper)
|
||||
@@ -340,6 +400,111 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseUp(location, button))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var child = GetChildAtRecursive(location);
|
||||
if (button == MouseButton.Right && child is Button b && b.Tag is Color c)
|
||||
{
|
||||
// Show menu
|
||||
var menu = new ContextMenu.ContextMenu();
|
||||
var replaceButton = menu.AddButton("Replace");
|
||||
replaceButton.Clicked += () => OnSavedColorReplace(b);
|
||||
var deleteButton = menu.AddButton("Delete");
|
||||
deleteButton.Clicked += () => OnSavedColorDelete(b);
|
||||
_disableEvents = true;
|
||||
menu.Show(this, location);
|
||||
menu.VisibleChanged += (c) => _disableEvents = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnSavedColorReplace(Button button)
|
||||
{
|
||||
// Prevent setting same color 2 times... because why...
|
||||
foreach (var color in _savedColors)
|
||||
{
|
||||
if (color == _value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set new Color in spot
|
||||
for (int i = 0; i < _savedColors.Count; i++)
|
||||
{
|
||||
var color = _savedColors[i];
|
||||
if (color == (Color)button.Tag)
|
||||
{
|
||||
color = _value;
|
||||
}
|
||||
}
|
||||
|
||||
// Set color of button to current value;
|
||||
button.BackgroundColor = _value;
|
||||
button.BackgroundColorHighlighted = _value;
|
||||
button.Text = "";
|
||||
button.Tag = _value;
|
||||
|
||||
// Save new colors
|
||||
var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>));
|
||||
Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors);
|
||||
}
|
||||
|
||||
private void OnSavedColorDelete(Button button)
|
||||
{
|
||||
_savedColors.Remove((Color)button.Tag);
|
||||
|
||||
foreach (var b in _savedColorButtons)
|
||||
{
|
||||
Children.Remove(b);
|
||||
}
|
||||
_savedColorButtons.Clear();
|
||||
|
||||
CreateAllSaveButtons();
|
||||
|
||||
// Save new colors
|
||||
var savedColors = JsonSerializer.Serialize(_savedColors, typeof(List<Color>));
|
||||
Editor.Instance.ProjectCache.SetCustomData("ColorPickerSavedColors", savedColors);
|
||||
}
|
||||
|
||||
private void CreateAllSaveButtons()
|
||||
{
|
||||
// Create saved color buttons
|
||||
for (int i = 0; i < _savedColors.Count; i++)
|
||||
{
|
||||
var savedColor = _savedColors[i];
|
||||
var savedColorButton = new Button(PickerMargin * (i + 1) + SavedColorButtonWidth * i, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
|
||||
{
|
||||
Parent = this,
|
||||
Tag = savedColor,
|
||||
BackgroundColor = savedColor,
|
||||
BackgroundColorHighlighted = savedColor,
|
||||
BackgroundColorSelected = savedColor.RGBMultiplied(0.8f),
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
_savedColorButtons.Add(savedColorButton);
|
||||
}
|
||||
if (_savedColors.Count < 8)
|
||||
{
|
||||
var savedColorButton = new Button(PickerMargin * (_savedColors.Count + 1) + SavedColorButtonWidth * _savedColors.Count, Height - SavedColorButtonHeight - PickerMargin, SavedColorButtonWidth, SavedColorButtonHeight)
|
||||
{
|
||||
Text = "+",
|
||||
Parent = this,
|
||||
Tag = null,
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
_savedColorButtons.Add(savedColorButton);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSubmit()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -200,7 +201,21 @@ namespace FlaxEditor.Gizmo
|
||||
ActorNode prefabRoot = GetPrefabRootInParent(actorNode);
|
||||
if (prefabRoot != null && actorNode != prefabRoot)
|
||||
{
|
||||
hit = WalkUpAndFindActorNodeBeforeSelection(actorNode, prefabRoot);
|
||||
bool isPrefabInSelection = false;
|
||||
foreach (var e in sceneEditing.Selection)
|
||||
{
|
||||
if (e is ActorNode ae && GetPrefabRootInParent(ae) == prefabRoot)
|
||||
{
|
||||
isPrefabInSelection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip selecting prefab root if we already had object from that prefab selected
|
||||
if (!isPrefabInSelection)
|
||||
{
|
||||
hit = WalkUpAndFindActorNodeBeforeSelection(actorNode, prefabRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -526,133 +526,6 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
||||
Engine::OnDraw();
|
||||
}
|
||||
|
||||
struct VisualScriptLocalManaged
|
||||
{
|
||||
MString* Value;
|
||||
MString* ValueTypeName;
|
||||
uint32 NodeId;
|
||||
int32 BoxId;
|
||||
};
|
||||
|
||||
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptLocals(int* localsCount)
|
||||
{
|
||||
MArray* result = nullptr;
|
||||
*localsCount = 0;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack && stack->Scope)
|
||||
{
|
||||
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
|
||||
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptLocal");
|
||||
ASSERT(mclass);
|
||||
result = MCore::Array::New(mclass, count);
|
||||
VisualScriptLocalManaged local;
|
||||
local.NodeId = MAX_uint32;
|
||||
if (stack->Scope->Parameters.Length() != 0)
|
||||
{
|
||||
auto s = stack;
|
||||
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
|
||||
s = s->PreviousFrame;
|
||||
if (s)
|
||||
local.NodeId = s->Node->ID;
|
||||
}
|
||||
VisualScriptLocalManaged* resultPtr = MCore::Array::GetAddress<VisualScriptLocalManaged>(result);
|
||||
for (int32 i = 0; i < stack->Scope->Parameters.Length(); i++)
|
||||
{
|
||||
auto& v = stack->Scope->Parameters[i];
|
||||
local.BoxId = i + 1;
|
||||
local.Value = MUtils::ToString(v.ToString());
|
||||
local.ValueTypeName = MUtils::ToString(v.Type.GetTypeName());
|
||||
resultPtr[i] = local;
|
||||
}
|
||||
for (int32 i = 0; i < stack->Scope->ReturnedValues.Count(); i++)
|
||||
{
|
||||
auto& v = stack->Scope->ReturnedValues[i];
|
||||
local.NodeId = v.NodeId;
|
||||
local.BoxId = v.BoxId;
|
||||
local.Value = MUtils::ToString(v.Value.ToString());
|
||||
local.ValueTypeName = MUtils::ToString(v.Value.Type.GetTypeName());
|
||||
resultPtr[stack->Scope->Parameters.Length() + i] = local;
|
||||
}
|
||||
*localsCount = count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct VisualScriptStackFrameManaged
|
||||
{
|
||||
MObject* Script;
|
||||
uint32 NodeId;
|
||||
int32 BoxId;
|
||||
};
|
||||
|
||||
DEFINE_INTERNAL_CALL(MArray*) EditorInternal_GetVisualScriptStackFrames(int* stackFramesCount)
|
||||
{
|
||||
MArray* result = nullptr;
|
||||
*stackFramesCount = 0;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack)
|
||||
{
|
||||
int32 count = 0;
|
||||
auto s = stack;
|
||||
while (s)
|
||||
{
|
||||
s = s->PreviousFrame;
|
||||
count++;
|
||||
}
|
||||
const MClass* mclass = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.Editor+VisualScriptStackFrame");
|
||||
ASSERT(mclass);
|
||||
result = MCore::Array::New(mclass, count);
|
||||
VisualScriptStackFrameManaged* resultPtr = MCore::Array::GetAddress<VisualScriptStackFrameManaged>(result);
|
||||
s = stack;
|
||||
count = 0;
|
||||
while (s)
|
||||
{
|
||||
VisualScriptStackFrameManaged frame;
|
||||
frame.Script = s->Script->GetOrCreateManagedInstance();
|
||||
frame.NodeId = s->Node->ID;
|
||||
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
|
||||
resultPtr[count] = frame;
|
||||
s = s->PreviousFrame;
|
||||
count++;
|
||||
}
|
||||
*stackFramesCount = count;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(VisualScriptStackFrameManaged) EditorInternal_GetVisualScriptPreviousScopeFrame()
|
||||
{
|
||||
VisualScriptStackFrameManaged frame;
|
||||
Platform::MemoryClear(&frame, sizeof(frame));
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack)
|
||||
{
|
||||
auto s = stack;
|
||||
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
|
||||
s = s->PreviousFrame;
|
||||
if (s && s->PreviousFrame)
|
||||
{
|
||||
s = s->PreviousFrame;
|
||||
frame.Script = s->Script->GetOrCreateManagedInstance();
|
||||
frame.NodeId = s->Node->ID;
|
||||
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocalManaged* local)
|
||||
{
|
||||
Variant v;
|
||||
if (VisualScripting::Evaluate(script, VisualScripting::GetThreadStackTop()->Instance, local->NodeId, local->BoxId, v))
|
||||
{
|
||||
local->Value = MUtils::ToString(v.ToString());
|
||||
local->ValueTypeName = MUtils::ToString(v.Type.GetTypeName());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
|
||||
{
|
||||
PROFILE_CPU_NAMED("DeserializeSceneObject");
|
||||
@@ -769,7 +642,7 @@ bool ManagedEditor::TryRestoreImportOptions(ModelTool::Options& options, String
|
||||
|
||||
// Get options from model
|
||||
FileSystem::NormalizePath(assetPath);
|
||||
return ImportModelFile::TryGetImportOptions(assetPath, options);
|
||||
return ImportModel::TryGetImportOptions(assetPath, options);
|
||||
}
|
||||
|
||||
bool ManagedEditor::Import(const String& inputPath, const String& outputPath, const AudioTool::Options& options)
|
||||
|
||||
@@ -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");
|
||||
@@ -487,6 +489,95 @@ void ManagedEditor::RequestStartPlayOnEditMode()
|
||||
Internal_RequestStartPlayOnEditMode->Invoke(GetManagedInstance(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
Array<ManagedEditor::VisualScriptStackFrame> ManagedEditor::GetVisualScriptStackFrames()
|
||||
{
|
||||
Array<VisualScriptStackFrame> result;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
auto s = stack;
|
||||
while (s)
|
||||
{
|
||||
VisualScriptStackFrame& frame = result.AddOne();
|
||||
frame.Script = s->Script;
|
||||
frame.NodeId = s->Node->ID;
|
||||
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
|
||||
s = s->PreviousFrame;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ManagedEditor::VisualScriptStackFrame ManagedEditor::GetVisualScriptPreviousScopeFrame()
|
||||
{
|
||||
VisualScriptStackFrame frame;
|
||||
Platform::MemoryClear(&frame, sizeof(frame));
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack)
|
||||
{
|
||||
auto s = stack;
|
||||
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
|
||||
s = s->PreviousFrame;
|
||||
if (s && s->PreviousFrame)
|
||||
{
|
||||
s = s->PreviousFrame;
|
||||
frame.Script = s->Script;
|
||||
frame.NodeId = s->Node->ID;
|
||||
frame.BoxId = s->Box ? s->Box->ID : MAX_uint32;
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
Array<ManagedEditor::VisualScriptLocal> ManagedEditor::GetVisualScriptLocals()
|
||||
{
|
||||
Array<VisualScriptLocal> result;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack && stack->Scope)
|
||||
{
|
||||
const int32 count = stack->Scope->Parameters.Length() + stack->Scope->ReturnedValues.Count();
|
||||
result.Resize(count);
|
||||
VisualScriptLocal local;
|
||||
local.NodeId = MAX_uint32;
|
||||
if (stack->Scope->Parameters.Length() != 0)
|
||||
{
|
||||
auto s = stack;
|
||||
while (s->PreviousFrame && s->PreviousFrame->Scope == stack->Scope)
|
||||
s = s->PreviousFrame;
|
||||
if (s)
|
||||
local.NodeId = s->Node->ID;
|
||||
}
|
||||
for (int32 i = 0; i < stack->Scope->Parameters.Length(); i++)
|
||||
{
|
||||
auto& v = stack->Scope->Parameters[i];
|
||||
local.BoxId = i + 1;
|
||||
local.Value = v.ToString();
|
||||
local.ValueTypeName = v.Type.GetTypeName();
|
||||
result[i] = local;
|
||||
}
|
||||
for (int32 i = 0; i < stack->Scope->ReturnedValues.Count(); i++)
|
||||
{
|
||||
auto& v = stack->Scope->ReturnedValues[i];
|
||||
local.NodeId = v.NodeId;
|
||||
local.BoxId = v.BoxId;
|
||||
local.Value = v.Value.ToString();
|
||||
local.ValueTypeName = v.Value.Type.GetTypeName();
|
||||
result[stack->Scope->Parameters.Length() + i] = local;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScriptLocal& local)
|
||||
{
|
||||
Variant v;
|
||||
const auto stack = VisualScripting::GetThreadStackTop();
|
||||
if (stack && VisualScripting::Evaluate(script, stack->Instance, local.NodeId, local.BoxId, v))
|
||||
{
|
||||
local.Value = v.ToString();
|
||||
local.ValueTypeName = v.Type.GetTypeName();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
ASSERT(!HasManagedInstance());
|
||||
|
||||
@@ -210,6 +210,31 @@ public:
|
||||
API_FUNCTION() static bool TryRestoreImportOptions(API_PARAM(Ref) AudioTool::Options& options, String assetPath);
|
||||
#endif
|
||||
|
||||
public:
|
||||
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(VisualScriptStackFrame);
|
||||
|
||||
API_FIELD() class VisualScript* Script;
|
||||
API_FIELD() uint32 NodeId;
|
||||
API_FIELD() int32 BoxId;
|
||||
};
|
||||
|
||||
API_STRUCT(Internal, NoDefault) struct VisualScriptLocal
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(VisualScriptLocal);
|
||||
|
||||
API_FIELD() String Value;
|
||||
API_FIELD() String ValueTypeName;
|
||||
API_FIELD() uint32 NodeId;
|
||||
API_FIELD() int32 BoxId;
|
||||
};
|
||||
|
||||
API_FUNCTION(Internal) static Array<VisualScriptStackFrame> GetVisualScriptStackFrames();
|
||||
API_FUNCTION(Internal) static VisualScriptStackFrame GetVisualScriptPreviousScopeFrame();
|
||||
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
|
||||
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
|
||||
|
||||
private:
|
||||
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
||||
|
||||
|
||||
@@ -126,29 +126,35 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
if (item != null && !item.GetImportPath(out string importPath))
|
||||
{
|
||||
// Check if input file is missing
|
||||
if (!System.IO.File.Exists(importPath))
|
||||
{
|
||||
Editor.LogWarning(string.Format("Cannot reimport asset \'{0}\'. File \'{1}\' does not exist.", item.Path, importPath));
|
||||
if (skipSettingsDialog)
|
||||
return;
|
||||
|
||||
// Ask user to select new file location
|
||||
var title = string.Format("Please find missing \'{0}\' file for asset \'{1}\'", importPath, item.ShortName);
|
||||
if (FileSystem.ShowOpenFileDialog(Editor.Windows.MainWindow, null, "All files (*.*)\0*.*\0", false, title, out var files))
|
||||
return;
|
||||
if (files != null && files.Length > 0)
|
||||
importPath = files[0];
|
||||
|
||||
// Validate file path again
|
||||
if (!System.IO.File.Exists(importPath))
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetReimportPath(item.ShortName, ref importPath, skipSettingsDialog))
|
||||
return;
|
||||
Import(importPath, item.Path, true, skipSettingsDialog, settings);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool GetReimportPath(string contextName, ref string importPath, bool skipSettingsDialog = false)
|
||||
{
|
||||
// Check if input file is missing
|
||||
if (!System.IO.File.Exists(importPath))
|
||||
{
|
||||
Editor.LogWarning(string.Format("Cannot reimport asset \'{0}\'. File \'{1}\' does not exist.", contextName, importPath));
|
||||
if (skipSettingsDialog)
|
||||
return true;
|
||||
|
||||
// Ask user to select new file location
|
||||
var title = string.Format("Please find missing \'{0}\' file for asset \'{1}\'", importPath, contextName);
|
||||
if (FileSystem.ShowOpenFileDialog(Editor.Windows.MainWindow, null, "All files (*.*)\0*.*\0", false, title, out var files))
|
||||
return true;
|
||||
if (files != null && files.Length > 0)
|
||||
importPath = files[0];
|
||||
|
||||
// Validate file path again
|
||||
if (!System.IO.File.Exists(importPath))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports the specified files.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace FlaxEditor.Modules
|
||||
private bool _updateOrFixedUpdateWasCalled;
|
||||
private long _breakpointHangFlag;
|
||||
private EditorWindow _enterPlayFocusedWindow;
|
||||
private Scene[] _scenesToReload;
|
||||
private Guid[] _scenesToReload;
|
||||
|
||||
internal SimulationModule(Editor editor)
|
||||
: base(editor)
|
||||
@@ -138,8 +138,15 @@ namespace FlaxEditor.Modules
|
||||
Editor.Simulation.RequestStartPlayScenes();
|
||||
return;
|
||||
}
|
||||
if (!FlaxEngine.Content.GetAssetInfo(firstScene.ID, out var info))
|
||||
{
|
||||
Editor.LogWarning("Invalid First Scene in Game Settings.");
|
||||
}
|
||||
|
||||
_scenesToReload = Level.Scenes;
|
||||
// Load scenes after entering the play mode
|
||||
_scenesToReload = new Guid[Level.ScenesCount];
|
||||
for (int i = 0; i < _scenesToReload.Length; i++)
|
||||
_scenesToReload[i] = Level.GetScene(i).ID;
|
||||
Level.UnloadAllScenes();
|
||||
Level.LoadScene(firstScene);
|
||||
|
||||
@@ -153,8 +160,8 @@ namespace FlaxEditor.Modules
|
||||
|
||||
Level.UnloadAllScenes();
|
||||
|
||||
foreach (var scene in _scenesToReload)
|
||||
Level.LoadScene(scene.ID);
|
||||
foreach (var sceneId in _scenesToReload)
|
||||
Level.LoadScene(sceneId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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,9 +7,37 @@ using Real = System.Single;
|
||||
#endif
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.CustomEditors.Dedicated;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.Scripting;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
/// <summary>
|
||||
/// Dedicated custom editor for BoxCollider objects.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(BoxCollider)), DefaultEditor]
|
||||
public class BoxColliderEditor : ActorEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
layout.Space(20f);
|
||||
layout.Button("Resize to Fit", Editor.Instance.CodeDocs.GetTooltip(new ScriptMemberInfo(typeof(BoxCollider).GetMethod("AutoResize")))).Button.Clicked += OnResizeClicked;
|
||||
}
|
||||
|
||||
private void OnResizeClicked()
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is BoxCollider collider)
|
||||
collider.AutoResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scene tree node for <see cref="BoxCollider"/> actor type.
|
||||
/// </summary>
|
||||
@@ -37,5 +65,18 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
|
||||
return base.RayCastSelf(ref ray, out distance, out normal);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PostSpawn()
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (Actor.HasPrefabLink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
((BoxCollider)Actor).AutoResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +334,11 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (Actor.HasPrefabLink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup for an initial spline
|
||||
var spline = (Spline)Actor;
|
||||
spline.AddSplineLocalPoint(Vector3.Zero, false);
|
||||
|
||||
@@ -61,10 +61,15 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (Actor.HasPrefabLink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup for default values
|
||||
var text = (SpriteRender)Actor;
|
||||
text.Material = FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.DefaultSpriteMaterial);
|
||||
text.Image = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.FlaxIconTexture);
|
||||
var sprite = (SpriteRender)Actor;
|
||||
sprite.Material = FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.DefaultSpriteMaterial);
|
||||
sprite.Image = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.FlaxIconTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (Actor.HasPrefabLink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup for default values
|
||||
var text = (TextRender)Actor;
|
||||
text.Text = "My Text";
|
||||
|
||||
@@ -7,6 +7,7 @@ using Real = System.Single;
|
||||
#endif
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
@@ -28,8 +29,33 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
{
|
||||
base.PostSpawn();
|
||||
|
||||
if (Actor.HasPrefabLink)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Rotate to match the space (GUI uses upper left corner as a root)
|
||||
Actor.LocalOrientation = Quaternion.Euler(0, -180, -180);
|
||||
bool canSpawn = true;
|
||||
foreach (var uiControl in Actor.GetChildren<UIControl>())
|
||||
{
|
||||
if (uiControl.Get<CanvasScaler>() == null)
|
||||
continue;
|
||||
canSpawn = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (canSpawn)
|
||||
{
|
||||
var uiControl = new UIControl
|
||||
{
|
||||
Name = "Canvas Scalar",
|
||||
Transform = Actor.Transform,
|
||||
Control = new CanvasScaler()
|
||||
};
|
||||
Root.Spawn(uiControl, Actor);
|
||||
}
|
||||
_treeNode.Expand();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -85,12 +85,20 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
{
|
||||
if (Parent is ActorTreeNode parent)
|
||||
{
|
||||
for (int i = 0; i < parent.ChildrenCount; i++)
|
||||
var anyChanged = false;
|
||||
var children = parent.Children;
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
if (parent.Children[i] is ActorTreeNode child && child.Actor)
|
||||
child._orderInParent = child.Actor.OrderInParent;
|
||||
if (children[i] is ActorTreeNode child && child.Actor)
|
||||
{
|
||||
var orderInParent = child.Actor.OrderInParent;
|
||||
anyChanged |= child._orderInParent != orderInParent;
|
||||
if (anyChanged)
|
||||
child._orderInParent = orderInParent;
|
||||
}
|
||||
}
|
||||
parent.SortChildren();
|
||||
if (anyChanged)
|
||||
parent.SortChildren();
|
||||
}
|
||||
else if (Actor)
|
||||
{
|
||||
@@ -266,7 +274,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 +289,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 =>
|
||||
{
|
||||
@@ -684,6 +698,10 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
if (thisHasScene != otherHasScene)
|
||||
return false;
|
||||
|
||||
// Reject dragging actors between prefab windows (different roots)
|
||||
if (!thisHasScene && ActorNode.Root != actorNode.Root)
|
||||
return false;
|
||||
|
||||
// Reject dragging parents and itself
|
||||
return actorNode.Actor != null && actorNode != ActorNode && actorNode.Find(Actor) == null;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1335,6 +1335,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Surface?.AddBatchedUndoAction(action);
|
||||
action.Do();
|
||||
Surface?.OnNodesConnected(this, other);
|
||||
Surface?.MarkAsEdited();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1911,6 +1912,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
var action = new StateMachineStateBase.AddRemoveTransitionAction(this);
|
||||
SourceState.Surface?.AddBatchedUndoAction(action);
|
||||
SourceState.Surface?.MarkAsEdited();
|
||||
action.Do();
|
||||
}
|
||||
|
||||
|
||||
@@ -493,7 +493,15 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 10,
|
||||
Title = "Blend Additive",
|
||||
Description = "Blend animation poses (with additive mode)",
|
||||
Description =
|
||||
"Blend animation poses (with additive mode)" +
|
||||
"\n" +
|
||||
"\nNote: " +
|
||||
"\nOrder of nodes matters, because Additive animation is appplayed on top of curent frame." +
|
||||
"\n" +
|
||||
"\nTip for blender users:" +
|
||||
"\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)" +
|
||||
"\nu need to place it in this order to get correct resoults",
|
||||
Flags = NodeFlags.AnimGraph,
|
||||
Size = new Float2(170, 80),
|
||||
DefaultValues = new object[]
|
||||
|
||||
@@ -288,6 +288,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
SetValue(2, ids);
|
||||
|
||||
// Force refresh UI
|
||||
ResizeAuto();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -752,6 +755,29 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDeleted(SurfaceNodeActions action)
|
||||
{
|
||||
// Unlink from the current parent (when deleted by user)
|
||||
var node = Node;
|
||||
if (node != null)
|
||||
{
|
||||
if (action == SurfaceNodeActions.User)
|
||||
{
|
||||
var decorators = node.DecoratorIds;
|
||||
decorators.Remove(ID);
|
||||
node.DecoratorIds = decorators;
|
||||
}
|
||||
else
|
||||
{
|
||||
node._decorators = null;
|
||||
node.ResizeAuto();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDeleted(action);
|
||||
}
|
||||
|
||||
public override void OnSurfaceCanEditChanged(bool canEdit)
|
||||
{
|
||||
base.OnSurfaceCanEditChanged(canEdit);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user