Compare commits
327 Commits
1682411bdb
...
wip
| Author | SHA1 | Date | |
|---|---|---|---|
| a45aa74aca | |||
| dbf5dd9e92 | |||
| b0ae2b4cd2 | |||
| ed8001ff8b | |||
| 6e2ed2bdbd | |||
| ba88bf8b0f | |||
|
|
56b2c96b3b | ||
|
|
5c06d413b0 | ||
| 1c17b77d1e | |||
| e24bb71e91 | |||
| 3382aabefe | |||
| 4ddc765ee4 | |||
| 5fd64ead62 | |||
| 30257929e5 | |||
| 980a112c57 | |||
| 98bbcbd442 | |||
| 9f8faf4f17 | |||
| 691b9458ec | |||
| b095acd4a5 | |||
| afbb8225d8 | |||
| 35678b06a8 | |||
| 96d39ecb30 | |||
| 2c7b11a691 | |||
| 83c288d739 | |||
| 8c6b853ee5 | |||
| b414d7d026 | |||
| ae6ec809b8 | |||
| f47214ae0a | |||
| bddd1b0984 | |||
| e2e77385b1 | |||
| f4c13032a2 | |||
| 43801d0824 | |||
| 16cd027bf3 | |||
| f361c4bbdb | |||
| c4f5777536 | |||
| c740d27b0e | |||
| 800b163de9 | |||
| 7f317d0fb6 | |||
| 714cdd84ad | |||
| 26b5172aea | |||
| 47b95f5650 | |||
| 989a5441f3 | |||
| 6394a7aae0 | |||
| beff9d5241 | |||
|
|
83c3201ef8 | ||
|
|
dcba97f84a | ||
|
|
ca6544204b | ||
|
|
1c3d1b623d | ||
|
|
bf21b0a267 | ||
|
|
afc4158dd3 | ||
|
|
09ead0cc7a | ||
|
|
f2e840577a | ||
|
|
345cbdb8d4 | ||
|
|
0ebda18669 | ||
|
|
efa081716f | ||
|
|
7225737984 | ||
|
|
0b1a64305a | ||
|
|
bfd972b96d | ||
|
|
25f26a7a91 | ||
|
|
d9ae41ed10 | ||
|
|
68877eebe3 | ||
|
|
5ed18c7448 | ||
|
|
1fda1d749d | ||
|
|
ac728f1a31 | ||
|
|
8beeea0da1 | ||
|
|
fc4b79239b | ||
|
|
618027b181 | ||
|
|
f97ead8a20 | ||
|
|
bae381430a | ||
|
|
1c3f7fcec0 | ||
|
|
65a219512c | ||
|
|
bb12562c2f | ||
|
|
b81b0b7616 | ||
|
|
bd9a5f03a4 | ||
|
|
9d5d80bf4a | ||
|
|
44e894f406 | ||
|
|
366b47ad80 | ||
|
|
b3508b9fe1 | ||
|
|
3f2eab5206 | ||
|
|
5bdf5da142 | ||
| c823257b79 | |||
|
|
937d369856 | ||
|
|
060bc0aaf8 | ||
|
|
c81ddd09cc | ||
|
|
015c4ab475 | ||
|
|
ccdf004404 | ||
|
|
9049093267 | ||
|
|
9d4d9ccf38 | ||
|
|
8b1d678f2e | ||
|
|
67db774a2f | ||
|
|
3cd951f0a0 | ||
|
|
0525ce2cb3 | ||
|
|
5e74ec01ce | ||
|
|
bbbc0c9d50 | ||
|
|
25067959eb | ||
|
|
086ddc96bb | ||
|
|
3394de0b93 | ||
| 16be2fc857 | |||
|
|
abd0c7dece | ||
|
|
ee540b3cb7 | ||
|
|
c146e156ec | ||
|
|
6efb015169 | ||
|
|
a982e0a111 | ||
|
|
84843f8cbb | ||
|
|
dccb43702e | ||
|
|
f459249f78 | ||
|
|
3ad369501a | ||
|
|
b0fe4373b0 | ||
|
|
9df5ed5b7f | ||
|
|
aa8add7b38 | ||
|
|
21f8dab5de | ||
|
|
4baa38c0cc | ||
|
|
3c091dc214 | ||
|
|
58090aa6d6 | ||
|
|
2521ed4ad5 | ||
|
|
6a5f22400d | ||
|
|
a5fffc0c9e | ||
|
|
e551ecbe5f | ||
| 561239a4b2 | |||
| 389b2e6148 | |||
| 9403b87788 | |||
| 64cceac913 | |||
| c523079f0e | |||
|
|
8542f78b0b | ||
|
|
da513972e8 | ||
|
|
be293a957a | ||
|
|
8e26591c0b | ||
|
|
4e31d436d5 | ||
|
|
b6f7914b14 | ||
|
|
9ffbe1f8ca | ||
|
|
4e0cd9e8a9 | ||
|
|
24f3dfe264 | ||
|
|
42fc62eb68 | ||
|
|
b1392be3a1 | ||
|
|
04dde7a3f2 | ||
|
|
44fae3838e | ||
|
|
f11306af24 | ||
|
|
4057dc189d | ||
|
|
fc98b5f1f0 | ||
|
|
4d6282a5b4 | ||
|
|
0e058b2590 | ||
|
|
a31279954a | ||
|
|
d25cb7a9da | ||
| 942124fdc3 | |||
| 9085874d4e | |||
| 2f5562f8eb | |||
| 6733e45729 | |||
| 37438afbf6 | |||
| 7c34b1c855 | |||
| 3dc2e55627 | |||
| c658dd72e7 | |||
| 5b8c81dfac | |||
| bf4ec5f91a | |||
| 15024b38b9 | |||
| 71ec415cc4 | |||
| 81b6f47d8a | |||
| e55fd18771 | |||
| fd97c2bdf2 | |||
| 6ca71a872d | |||
| 18e92425bb | |||
| 3feebe8910 | |||
| 9fc7fc7a2e | |||
| 642d90a293 | |||
| f5313b9ffd | |||
|
|
7abed39473 | ||
| ffc40ba634 | |||
| 84f3cda190 | |||
| 0f20f387fc | |||
| 67093a0d28 | |||
| 63eaf1adf2 | |||
| 28d167b4f8 | |||
| 7bff09eeb9 | |||
| 5afde966ef | |||
| 5df1f32305 | |||
| 670f2ee2b0 | |||
| 5abf336696 | |||
| 7ae0a65c0e | |||
| 9e88233957 | |||
| d0a4213538 | |||
| b2467edc0f | |||
| 94e398a6b3 | |||
| e5ca67618f | |||
| 2da908d9b8 | |||
| 34f187161c | |||
| 0e5e0169bf | |||
| f318d3aadc | |||
| 43e38df8b0 | |||
| 86b999f6a4 | |||
| 553ca7d71c | |||
| 2594cc4546 | |||
| 2cd03eceaa | |||
| d8feec325a | |||
| 71b7f110e6 | |||
|
|
1b04c9a7b1 | ||
|
|
6a27e5338a | ||
|
|
5ad323c7cb | ||
|
|
9c065d55e0 | ||
|
|
1475075b00 | ||
|
|
702564366d | ||
|
|
e2fd3891d1 | ||
| f54e961f11 | |||
|
|
aabd70fbe7 | ||
| 428ebf7fd7 | |||
|
|
72f16d738f | ||
|
|
475818554d | ||
|
|
8ebb3a3215 | ||
|
|
2085a0bf25 | ||
|
|
d829461def | ||
|
|
2d169fdcd8 | ||
|
|
53ba5968fd | ||
|
|
cc735a1b6a | ||
|
|
970af7bdc8 | ||
|
|
2ff6a6dd9a | ||
|
|
ae3149c9c0 | ||
|
|
1a1bd56802 | ||
|
|
25b566b348 | ||
|
|
4fb95a704a | ||
|
|
5f09ef4c1f | ||
|
|
7bc099c32c | ||
|
|
9a59d0c5ed | ||
|
|
275ca296fa | ||
|
|
57af076c8d | ||
|
|
f905c49f0b | ||
|
|
c72fac335f | ||
|
|
030befdcaa | ||
|
|
3a591577ad | ||
|
|
8f9eaddbe5 | ||
|
|
ec11a79f55 | ||
|
|
55fd198102 | ||
|
|
425699c4b0 | ||
| 10a906d51b | |||
| f61779119b | |||
| af3badaeef | |||
|
|
f17d6f62ab | ||
|
|
ae3d437539 | ||
|
|
99b737eb14 | ||
|
|
4add5dcf49 | ||
|
|
a204ada6d3 | ||
|
|
bdc7f0760f | ||
|
|
07ef2f03d5 | ||
|
|
b5437a9097 | ||
|
|
890c3e75c3 | ||
|
|
7fcf8c2d4c | ||
|
|
3796b0ccae | ||
|
|
bc18ddc04b | ||
|
|
90316dfa52 | ||
|
|
55fa372197 | ||
|
|
563f0b9ab4 | ||
|
|
30ea3bc9c2 | ||
|
|
07b9e5bfdd | ||
|
|
f274639e94 | ||
|
|
7ac2376231 | ||
|
|
01d1dbba6c | ||
|
|
ca995093b6 | ||
|
|
f36d3a11ab | ||
|
|
06a04167c7 | ||
|
|
e2df7a1e85 | ||
|
|
80f5b554cd | ||
|
|
f10404a948 | ||
|
|
a9580b9b46 | ||
|
|
3d76a99c9b | ||
|
|
eaeeea6a81 | ||
|
|
b546e4a332 | ||
|
|
281e13b42c | ||
|
|
8451439abb | ||
|
|
95c9df2581 | ||
|
|
2699755581 | ||
|
|
99b0fbee07 | ||
|
|
f153c67c0e | ||
|
|
fa8857be0e | ||
|
|
2260236fa6 | ||
|
|
cb7fc6141d | ||
|
|
77c48c037e | ||
|
|
ccbcab9793 | ||
|
|
e87bb2325b | ||
|
|
13863344d2 | ||
|
|
3133ebbd83 | ||
|
|
bff25a8dd8 | ||
|
|
a9d0f62039 | ||
|
|
5335594cb5 | ||
|
|
3f201c3863 | ||
|
|
3dc3406230 | ||
|
|
0b99cb6de5 | ||
|
|
deab78d6b1 | ||
|
|
45c01e7ada | ||
|
|
bcc8544c46 | ||
|
|
597bbf1f30 | ||
|
|
67b5b74588 | ||
|
|
39f2f0ccdf | ||
|
|
6ad2cd0697 | ||
|
|
ef01a4afeb | ||
|
|
12b98f2df1 | ||
|
|
99ba59d02a | ||
|
|
7eb2088af0 | ||
|
|
a66cb4d1b2 | ||
|
|
22914dc232 | ||
|
|
5af13bcc93 | ||
|
|
867f7d0143 | ||
|
|
26d0b9a42c | ||
|
|
f2e4fe300b | ||
|
|
a313db22d2 | ||
|
|
e53eddaba5 | ||
|
|
f71e731e54 | ||
|
|
cb6ab6a647 | ||
|
|
899528e087 | ||
|
|
6a8814c99a | ||
|
|
88703d721b | ||
|
|
36d4417905 | ||
|
|
873491eca2 | ||
|
|
3ba1ebb847 | ||
|
|
f9e125f795 | ||
|
|
0991628a78 | ||
|
|
703e83cd48 | ||
|
|
1fca41b31a | ||
|
|
8b3f1ca019 | ||
|
|
a50c21cf36 | ||
|
|
ecb80e0f34 | ||
|
|
aded4bfdeb | ||
|
|
22764f5362 | ||
|
|
1b84f57a5b | ||
|
|
23f4a82bbc | ||
|
|
9fbfc83535 | ||
|
|
ad8d84bfd7 | ||
|
|
4257f1e2ac | ||
|
|
8166970038 | ||
|
|
88530606df | ||
|
|
d9b3443818 |
4
.github/workflows/build_linux.yml
vendored
4
.github/workflows/build_linux.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev libwayland-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
|
||||
29
.github/workflows/cd.yml
vendored
29
.github/workflows/cd.yml
vendored
@@ -1,12 +1,13 @@
|
||||
name: Continuous Deployment
|
||||
on:
|
||||
schedule:
|
||||
- cron: '15 4 * * *'
|
||||
- cron: '15 6 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
DOTNET_NOLOGO: true
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -20,7 +21,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -35,12 +36,12 @@ jobs:
|
||||
run: |
|
||||
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows-Editor
|
||||
path: Output/Editor.zip
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows-EditorDebugSymbols
|
||||
path: Output/EditorDebugSymbols.zip
|
||||
@@ -53,7 +54,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -68,7 +69,7 @@ jobs:
|
||||
run: |
|
||||
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Windows-Game
|
||||
path: Output/Windows.zip
|
||||
@@ -83,7 +84,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
@@ -101,7 +102,7 @@ jobs:
|
||||
run: |
|
||||
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Linux-Editor
|
||||
path: Output/FlaxEditorLinux.zip
|
||||
@@ -114,7 +115,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
@@ -132,7 +133,7 @@ jobs:
|
||||
run: |
|
||||
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Linux-Game
|
||||
path: Output/Linux.zip
|
||||
@@ -147,7 +148,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -162,7 +163,7 @@ jobs:
|
||||
run: |
|
||||
./PackageEditor.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Mac-Editor
|
||||
path: Output/FlaxEditorMac.zip
|
||||
@@ -175,7 +176,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
git lfs pull
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -190,7 +191,7 @@ jobs:
|
||||
run: |
|
||||
./PackagePlatforms.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Mac-Game
|
||||
path: Output/Mac.zip
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
|
||||
- name: Build
|
||||
run: |
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Redirect to our own Git LFS server
|
||||
[lfs]
|
||||
url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
||||
locksverify = false
|
||||
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
||||
locksverify = false
|
||||
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
Binary file not shown.
25
Content/Editor/Scripting/GamePluginTemplate.cs
Normal file
25
Content/Editor/Scripting/GamePluginTemplate.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
%copyright%using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace %namespace%;
|
||||
|
||||
/// <summary>
|
||||
/// %class% GamePlugin.
|
||||
/// </summary>
|
||||
public class %class% : GamePlugin
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Deinitialize()
|
||||
{
|
||||
base.Deinitialize();
|
||||
|
||||
}
|
||||
}
|
||||
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
Binary file not shown.
@@ -13,6 +13,7 @@
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false,
|
||||
"UseDotNet": true
|
||||
"UseDotNet": true,
|
||||
"UseSDL": true
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ if errorlevel 1 goto BuildToolFailed
|
||||
|
||||
:: Build bindings for all editor configurations
|
||||
echo Building C# bindings...
|
||||
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
|
||||
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
|
||||
|
||||
popd
|
||||
echo Done!
|
||||
|
||||
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
|
||||
# Build bindings for all editor configurations
|
||||
echo Building C# bindings...
|
||||
# TODO: Detect the correct architecture here
|
||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor
|
||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame
|
||||
|
||||
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
|
||||
# Build bindings for all editor configurations
|
||||
echo Building C# bindings...
|
||||
# TODO: Detect the correct architecture here
|
||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor
|
||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame
|
||||
|
||||
@@ -31,7 +31,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Install Visual Studio 2022 or newer
|
||||
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
|
||||
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
|
||||
* Install .NET 8 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Install .NET 8 or 9 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Install Git with LFS
|
||||
* Clone repo (with LFS)
|
||||
* Run **GenerateProjectFiles.bat**
|
||||
@@ -44,8 +44,9 @@ Follow the instructions below to compile and run the engine from source.
|
||||
## Linux
|
||||
|
||||
* Install Visual Studio Code
|
||||
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Ubuntu: `sudo apt install dotnet-sdk-8.0`
|
||||
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
@@ -67,12 +68,12 @@ Follow the instructions below to compile and run the engine from source.
|
||||
## Mac
|
||||
|
||||
* Install XCode
|
||||
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Clone repo (with LFS)
|
||||
* Run `GenerateProjectFiles.command`
|
||||
* Open workspace with XCode or Visual Studio Code
|
||||
* Build and run (configuration `Editor.Mac.Development`)
|
||||
* Build and run (configuration `Editor.Mac.Development`)
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
|
||||
@@ -750,7 +750,8 @@ namespace FlaxEditor.Content
|
||||
|
||||
// Draw short name
|
||||
Render2D.PushClip(ref textRect);
|
||||
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, 0.95f);
|
||||
var scale = 0.95f * view.ViewScale;
|
||||
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, scale);
|
||||
Render2D.PopClip();
|
||||
|
||||
if (IsBeingCut)
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeDescription => Path.EndsWith(".h") ? "C++ Header File" : "C++ Source Code";
|
||||
public override string TypeDescription => Path.EndsWith(".h") || Path.EndsWith(".hpp") ? "C++ Header File" : "C++ Source Code";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128;
|
||||
|
||||
@@ -106,6 +106,23 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Context proxy object for C# GamePlugin files.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.CSharpProxy" />
|
||||
[ContentContextMenu("New/C#/C# GamePlugin")]
|
||||
public class CSharpGamePluginProxy : CSharpProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string Name => "C# GamePlugin";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void GetTemplatePath(out string path)
|
||||
{
|
||||
path = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/GamePluginTemplate.cs");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Context proxy object for empty C# files.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Content.Create;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
@@ -84,18 +86,67 @@ namespace FlaxEditor.Content
|
||||
|
||||
if (_element != null)
|
||||
{
|
||||
// Define the rule for the types that can be used to create a json data asset
|
||||
_element.CustomControl.CheckValid += type =>
|
||||
type.Type != null &&
|
||||
type.IsClass &&
|
||||
type.Type.IsVisible &&
|
||||
!type.IsAbstract &&
|
||||
!type.IsGenericType &&
|
||||
type.Type.GetConstructor(Type.EmptyTypes) != null &&
|
||||
!typeof(FlaxEngine.GUI.Control).IsAssignableFrom(type.Type) &&
|
||||
!typeof(FlaxEngine.Object).IsAssignableFrom(type.Type);
|
||||
_element.CustomControl.CheckValid += OnCheckValidJsonAssetType;
|
||||
}
|
||||
}
|
||||
|
||||
private static Type[] BlacklistedClasses =
|
||||
[
|
||||
typeof(System.Attribute),
|
||||
typeof(FlaxEngine.Object),
|
||||
typeof(FlaxEngine.GUI.Control),
|
||||
];
|
||||
|
||||
private static Type[] BlacklistedStructs =
|
||||
[
|
||||
typeof(Float2),
|
||||
typeof(Float3),
|
||||
typeof(Float4),
|
||||
typeof(Double2),
|
||||
typeof(Double3),
|
||||
typeof(Double4),
|
||||
typeof(Vector2),
|
||||
typeof(Vector3),
|
||||
typeof(Vector4),
|
||||
typeof(Half2),
|
||||
typeof(Half3),
|
||||
typeof(Half4),
|
||||
typeof(Int2),
|
||||
typeof(Int3),
|
||||
typeof(Int4),
|
||||
typeof(Transform),
|
||||
typeof(Quaternion),
|
||||
typeof(BoundingBox),
|
||||
typeof(BoundingSphere),
|
||||
typeof(BoundingFrustum),
|
||||
typeof(Ray),
|
||||
typeof(Plane),
|
||||
typeof(Matrix),
|
||||
typeof(Color),
|
||||
typeof(Color32),
|
||||
typeof(FloatR11G11B10),
|
||||
typeof(FloatR10G10B10A2),
|
||||
typeof(FlaxEngine.Half),
|
||||
];
|
||||
|
||||
private static bool OnCheckValidJsonAssetType(ScriptType type)
|
||||
{
|
||||
// Define the rule for the types that can be used to create a json data asset
|
||||
var mType = type.Type;
|
||||
if (mType == null ||
|
||||
type.IsAbstract ||
|
||||
type.IsStatic ||
|
||||
type.IsGenericType ||
|
||||
!mType.IsVisible)
|
||||
return false;
|
||||
if (type.IsClass)
|
||||
return mType.GetConstructor(Type.EmptyTypes) != null && BlacklistedClasses.FirstOrDefault(x => x.IsAssignableFrom(mType)) == null;
|
||||
if (type.IsStructure)
|
||||
return !type.IsPrimitive &&
|
||||
!type.IsVoid &&
|
||||
!BlacklistedStructs.Contains(mType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +226,7 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
_thumbnail = SpriteHandle.Invalid;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with overriden thumbnail.
|
||||
/// </summary>
|
||||
@@ -196,7 +247,7 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
Editor.SaveJsonAsset(outputPath, new T());
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
|
||||
@@ -496,7 +496,7 @@ namespace FlaxEditor.Content.Thumbnails
|
||||
// Prepare requests
|
||||
bool isAnyReady = false;
|
||||
int checks = Mathf.Min(10, _requests.Count);
|
||||
for (int i = 0; i < checks; i++)
|
||||
for (int i = 0; i < checks && i < _requests.Count; i++)
|
||||
{
|
||||
var request = _requests[i];
|
||||
try
|
||||
|
||||
@@ -671,11 +671,14 @@ bool GameCookerImpl::Build()
|
||||
MCore::Thread::Attach();
|
||||
|
||||
// Build Started
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildStarted(data);
|
||||
data.InitProgress(Steps.Count());
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
{
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildStarted(data);
|
||||
data.InitProgress(Steps.Count());
|
||||
}
|
||||
|
||||
// Execute all steps in a sequence
|
||||
bool failed = false;
|
||||
@@ -741,10 +744,13 @@ bool GameCookerImpl::Build()
|
||||
}
|
||||
IsRunning = false;
|
||||
CancelFlag = 0;
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
{
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||
}
|
||||
Delete(Data);
|
||||
Data = nullptr;
|
||||
|
||||
|
||||
@@ -364,6 +364,33 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
}
|
||||
#endif
|
||||
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
|
||||
|
||||
if (platformSettings->BuildAAB)
|
||||
{
|
||||
// .aab
|
||||
{
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT(":app:bundle") : TEXT(":app:bundleDebug"));
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
const int32 result = Platform::CreateProcess(procSettings);
|
||||
if (result != 0)
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into .aab package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Copy result package
|
||||
const String aab = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/bundle/release/app-release.aab") : TEXT("app/build/outputs/bundle/debug/app-debug.aab"));
|
||||
const String outputAab = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".aab");
|
||||
if (FileSystem::CopyFile(outputAab, aab))
|
||||
{
|
||||
LOG(Error, "Failed to copy .aab package from {0} to {1}", aab, outputAab);
|
||||
return true;
|
||||
}
|
||||
LOG(Info, "Output Android AAB application package: {0} (size: {1} MB)", outputAab, FileSystem::GetFileSize(outputAab) / 1024 / 1024);
|
||||
}
|
||||
|
||||
// .apk
|
||||
{
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
@@ -371,20 +398,20 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
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));
|
||||
data.Error(String::Format(TEXT("Failed to build Gradle project into .apk package (result code: {0}). See log for more info."), result));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy result package
|
||||
const String apk = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/apk/release/app-release-unsigned.apk") : TEXT("app/build/outputs/apk/debug/app-debug.apk"));
|
||||
const String outputApk = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".apk");
|
||||
if (FileSystem::CopyFile(outputApk, apk))
|
||||
{
|
||||
LOG(Error, "Failed to copy package from {0} to {1}", apk, outputApk);
|
||||
LOG(Error, "Failed to copy .apk package from {0} to {1}", apk, outputApk);
|
||||
return true;
|
||||
}
|
||||
LOG(Info, "Output Android application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
||||
LOG(Info, "Output Android APK application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1277,6 +1277,8 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
assetStats.Count++;
|
||||
assetStats.ContentSize += FileSystem::GetFileSize(cookedFilePath);
|
||||
|
||||
LOG(Info, "Cooked size of {0}: {1}KB", assetId, (FileSystem::GetFileSize(cookedFilePath) / (1024)));
|
||||
|
||||
if (packageBuilder.Add(data, i->Value, cookedFilePath))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -214,6 +214,33 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
FileSystem::NormalizePath(srcDotnet);
|
||||
LOG(Info, "Using .NET Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||
|
||||
// Get major Version
|
||||
Array<String> pathParts;
|
||||
srcDotnet.Split('/', pathParts);
|
||||
String version;
|
||||
for (int i = 0; i < pathParts.Count(); i++)
|
||||
{
|
||||
if (pathParts[i] == TEXT("runtimes"))
|
||||
{
|
||||
Array<String> versionParts;
|
||||
pathParts[i - 1].Split('.', versionParts);
|
||||
if (!versionParts.IsEmpty())
|
||||
{
|
||||
const String majorVersion = versionParts[0].TrimTrailing();
|
||||
int32 versionNum;
|
||||
StringUtils::Parse(*majorVersion, majorVersion.Length(), &versionNum);
|
||||
if (Math::IsInRange(versionNum, GAME_BUILD_DOTNET_RUNTIME_MIN_VER, GAME_BUILD_DOTNET_RUNTIME_MAX_VER)) // Check for major part
|
||||
version = majorVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
data.Error(TEXT("Failed to find supported .NET version for the current host platform."));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deploy runtime files
|
||||
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
||||
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
|
||||
@@ -226,14 +253,14 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
// AOT runtime files inside Engine Platform folder
|
||||
packFolder /= TEXT("Dotnet");
|
||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
||||
srcDotnetLibs = packFolder / TEXT("lib/net8.0");
|
||||
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||
srcDotnetLibs = packFolder / String::Format(TEXT("lib/net{}.0"), version);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder but placed for AOT
|
||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
||||
srcDotnetLibs /= TEXT("../lib/net8.0");
|
||||
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -241,14 +268,14 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// Runtime files inside Engine Platform folder
|
||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
||||
srcDotnetLibs /= TEXT("lib/net8.0");
|
||||
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||
srcDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Runtime files inside Dotnet SDK folder
|
||||
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
|
||||
srcDotnetLibs /= TEXT("../lib/net8.0");
|
||||
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
|
||||
}
|
||||
}
|
||||
LOG(Info, "Copying .NET files from {} to {}", packFolder, dstDotnet);
|
||||
@@ -273,6 +300,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Globalization.Native.so");
|
||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
|
||||
break;
|
||||
case BuildPlatform::iOSARM64:
|
||||
@@ -387,9 +415,9 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/WhiteTexture"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensStarburst"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensColor"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensDirt"));
|
||||
//data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensStarburst"));
|
||||
//data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensColor"));
|
||||
//data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensDirt"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Circle"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Hexagon"));
|
||||
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Octagon"));
|
||||
|
||||
@@ -883,7 +883,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
protected virtual void ClearToken()
|
||||
{
|
||||
ParentEditor.ClearToken();
|
||||
ParentEditor?.ClearToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,15 @@ namespace FlaxEditor.CustomEditors
|
||||
Presenter.AfterLayout?.Invoke(layout);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
Editor = null;
|
||||
_overrideEditor = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnModified()
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
@@ -67,12 +68,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Use default prefab instance as a reference for the editor
|
||||
Values.SetReferenceValue(prefabInstance);
|
||||
|
||||
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter)
|
||||
// Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
|
||||
var prefabId = prefab.ID;
|
||||
Editor.GetPrefabNestedObject(ref prefabId, ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
|
||||
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
|
||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||
panel.CustomControl.Height = 20.0f;
|
||||
panel.CustomControl.SlotsVertically = 1;
|
||||
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
|
||||
{
|
||||
// Add some UI
|
||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||
panel.CustomControl.Height = 20.0f;
|
||||
panel.CustomControl.SlotsVertically = 1;
|
||||
var targetPrefab = nestedPrefab ?? prefab;
|
||||
panel.CustomControl.SlotsHorizontally = 3;
|
||||
|
||||
// Selecting actor prefab asset
|
||||
@@ -80,22 +85,21 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
selectPrefab.Button.Clicked += () =>
|
||||
{
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
||||
Editor.Instance.Windows.ContentWin.Select(targetPrefab);
|
||||
};
|
||||
|
||||
// Edit selected prefab asset
|
||||
var editPrefab = panel.Button("Edit Prefab");
|
||||
editPrefab.Button.Clicked += () =>
|
||||
{
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
||||
Editor.Instance.Windows.ContentWin.Open(Editor.Instance.Windows.ContentWin.View.Selection[0]);
|
||||
};
|
||||
|
||||
// Viewing changes applied to this actor
|
||||
var viewChanges = panel.Button("View Changes");
|
||||
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
||||
editPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(targetPrefab.ID));
|
||||
}
|
||||
else
|
||||
{
|
||||
panel.CustomControl.SlotsHorizontally = 1;
|
||||
}
|
||||
|
||||
// Viewing changes applied to this actor
|
||||
var viewChanges = panel.Button("View Changes");
|
||||
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
||||
|
||||
// Link event to update editor on prefab apply
|
||||
_linkedPrefabId = prefab.ID;
|
||||
@@ -202,7 +206,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (_linkedPrefabId != Guid.Empty)
|
||||
{
|
||||
_linkedPrefabId = Guid.Empty;
|
||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplying;
|
||||
Editor.Instance.Prefabs.PrefabApplying -= OnPrefabApplying;
|
||||
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.Surface;
|
||||
using FlaxEngine;
|
||||
@@ -35,6 +36,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
|
||||
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
|
||||
Values);
|
||||
if (!parameters.Any())
|
||||
group.Label("No parameters", TextAlignment.Center);
|
||||
_parametersAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private int _firstTimeShow;
|
||||
private BezierCurveEditor<T> _curve;
|
||||
private Splitter _splitter;
|
||||
private string _heightCachedPath;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var item = layout.CustomContainer<BezierCurveEditor<T>>();
|
||||
_curve = item.CustomControl;
|
||||
_curve.Height = 120.0f;
|
||||
var height = 120.0f;
|
||||
var presenter = Presenter;
|
||||
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||
{
|
||||
// Try to restore curve height
|
||||
_heightCachedPath = layout.GetLayoutCachePath("Height");
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
|
||||
height = cachedHeight;
|
||||
}
|
||||
_curve.Height = height;
|
||||
_curve.Edited += OnCurveEdited;
|
||||
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
||||
_splitter = new Splitter
|
||||
@@ -45,7 +55,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
private void OnSplitterMoved(Float2 location)
|
||||
{
|
||||
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
||||
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
||||
|
||||
// Cache curve height
|
||||
if (_heightCachedPath != null)
|
||||
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -133,13 +147,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private int _firstTimeShow;
|
||||
private LinearCurveEditor<T> _curve;
|
||||
private Splitter _splitter;
|
||||
private string _heightCachedPath;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var item = layout.CustomContainer<LinearCurveEditor<T>>();
|
||||
_curve = item.CustomControl;
|
||||
_curve.Height = 120.0f;
|
||||
var height = 120.0f;
|
||||
var presenter = Presenter;
|
||||
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||
{
|
||||
// Try to restore curve height
|
||||
_heightCachedPath = layout.GetLayoutCachePath("Height");
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
|
||||
height = cachedHeight;
|
||||
}
|
||||
_curve.Height = height;
|
||||
_curve.Edited += OnCurveEdited;
|
||||
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
||||
_splitter = new Splitter
|
||||
@@ -164,6 +188,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private void OnSplitterMoved(Float2 location)
|
||||
{
|
||||
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
||||
|
||||
// Cache curve height
|
||||
if (_heightCachedPath != null)
|
||||
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -186,12 +186,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
foreach (var file in files)
|
||||
FindNewKeysCSharp(file, newKeys, allKeys);
|
||||
|
||||
// C++
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories);
|
||||
// C/C++
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.c", SearchOption.AllDirectories)).ToArray();
|
||||
filesCount += files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysCpp(file, newKeys, allKeys);
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories);
|
||||
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.hpp", SearchOption.AllDirectories)).ToArray();;
|
||||
filesCount += files.Length;
|
||||
foreach (var file in files)
|
||||
FindNewKeysCpp(file, newKeys, allKeys);
|
||||
|
||||
@@ -53,6 +53,9 @@ public class ModelPrefabEditor : GenericEditor
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the import path UI
|
||||
Utilities.Utils.CreateImportPathUI(layout, modelPrefab.ImportPath, false);
|
||||
|
||||
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
|
||||
_reimportButton = button.Button;
|
||||
_reimportButton.Clicked += OnReimport;
|
||||
|
||||
@@ -117,6 +117,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var data = SurfaceUtils.InitGraphParameters(parametersGroup);
|
||||
SurfaceUtils.DisplayGraphParameters(group, data, ParameterGet, ParameterSet, Values, ParameterDefaultValue);
|
||||
}
|
||||
|
||||
if (!parameters.Any())
|
||||
groups.Label("No parameters", TextAlignment.Center);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1057,6 +1057,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_scriptToggles = null;
|
||||
_scripts.Clear();
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -122,7 +123,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (!HasDifferentValues)
|
||||
var differentValues = HasDifferentValues;
|
||||
Picker.DifferentValues = differentValues;
|
||||
if (!differentValues)
|
||||
{
|
||||
_isRefreshing = true;
|
||||
var value = Values[0];
|
||||
@@ -156,6 +159,17 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
private Rectangle DropdownRect => new Rectangle(Width - DropdownIconSize - DropdownIconMargin, DropdownIconMargin, DropdownIconSize, DropdownIconSize);
|
||||
|
||||
public Action ShowPicker;
|
||||
public Action<ContentItem> OnAssetDropped;
|
||||
|
||||
private DragItems _dragItems;
|
||||
private DragHandlers _dragHandlers;
|
||||
private bool _hasValidDragOver;
|
||||
private Func<ContentItem, bool> _validate;
|
||||
|
||||
public void SetValidationMethod(Func<ContentItem, bool> validate)
|
||||
{
|
||||
_validate = validate;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
@@ -164,6 +178,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
var dropdownRect = DropdownRect;
|
||||
Render2D.DrawSprite(style.ArrowDown, dropdownRect, Enabled ? (DropdownRect.Contains(PointFromWindow(RootWindow.MousePosition)) ? style.BorderSelected : style.Foreground) : style.ForegroundDisabled);
|
||||
|
||||
// Check if drag is over
|
||||
if (IsDragOver && _hasValidDragOver)
|
||||
{
|
||||
var bounds = new Rectangle(Float2.Zero, Size);
|
||||
Render2D.FillRectangle(bounds, style.Selection);
|
||||
Render2D.DrawRectangle(bounds, style.SelectionBorder);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
@@ -207,6 +229,68 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private DragDropEffect DragEffect => _hasValidDragOver ? DragDropEffect.Move : DragDropEffect.None;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
|
||||
{
|
||||
base.OnDragEnter(ref location, data);
|
||||
|
||||
// Ensure to have valid drag helpers (uses lazy init)
|
||||
if (_dragItems == null)
|
||||
_dragItems = new DragItems(ValidateDragAsset);
|
||||
if (_dragHandlers == null)
|
||||
{
|
||||
_dragHandlers = new DragHandlers
|
||||
{
|
||||
_dragItems,
|
||||
};
|
||||
}
|
||||
|
||||
_hasValidDragOver = _dragHandlers.OnDragEnter(data) != DragDropEffect.None;
|
||||
|
||||
|
||||
return DragEffect;
|
||||
}
|
||||
|
||||
private bool ValidateDragAsset(ContentItem contentItem)
|
||||
{
|
||||
// Load or get asset
|
||||
return _validate?.Invoke(contentItem) ?? false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||
{
|
||||
base.OnDragMove(ref location, data);
|
||||
|
||||
return DragEffect;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDragLeave()
|
||||
{
|
||||
_hasValidDragOver = false;
|
||||
_dragHandlers.OnDragLeave();
|
||||
|
||||
base.OnDragLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
|
||||
{
|
||||
var result = DragEffect;
|
||||
|
||||
base.OnDragDrop(ref location, data);
|
||||
|
||||
if (_dragItems.HasValidDrag)
|
||||
{
|
||||
OnAssetDropped(_dragItems.Objects[0]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private TextBoxWithPicker _textBox;
|
||||
@@ -221,13 +305,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
|
||||
_validator = new AssetPickerValidator(ScriptType.Null);
|
||||
_textBox = layout.Custom<TextBoxWithPicker>().CustomControl;
|
||||
_textBox.ShowPicker = OnShowPicker;
|
||||
_textBox.OnAssetDropped = OnItemDropped;
|
||||
_textBox.EditEnd += OnEditEnd;
|
||||
_validator = new AssetPickerValidator(ScriptType.Null);
|
||||
_textBox.SetValidationMethod(_validator.IsValid);
|
||||
AssetRefEditor.ApplyAssetReferenceAttribute(Values, out _, _validator);
|
||||
}
|
||||
|
||||
private void OnItemDropped(ContentItem item)
|
||||
{
|
||||
SetPickerPath(item);
|
||||
}
|
||||
|
||||
private void OnShowPicker()
|
||||
{
|
||||
if (_validator.AssetType != ScriptType.Null)
|
||||
@@ -285,12 +377,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (!HasDifferentValues)
|
||||
{
|
||||
_isRefreshing = true;
|
||||
_textBox.Text = GetPath();
|
||||
_isRefreshing = false;
|
||||
}
|
||||
_isRefreshing = true;
|
||||
_textBox.Text = HasDifferentValues ? "Multiple Values" : GetPath();
|
||||
_isRefreshing = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_label = layout.ClickableLabel(Path).CustomControl;
|
||||
_label.Margin = new Margin(0, 20.0f, 0, 0);
|
||||
_label.ClipText = true;
|
||||
_label.RightClick += ShowPicker;
|
||||
var button = new Button
|
||||
{
|
||||
|
||||
@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
@@ -40,6 +42,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
private DragScripts _dragScripts;
|
||||
private DragHandlers _dragHandlers;
|
||||
|
||||
/// <summary>
|
||||
/// The presenter using this control.
|
||||
/// </summary>
|
||||
public IPresenterOwner PresenterContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the allowed objects type (given type and all sub classes). Must be <see cref="Object"/> type of any subclass.
|
||||
/// </summary>
|
||||
@@ -129,6 +136,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// </summary>
|
||||
public Func<Object, ScriptType, bool> CheckValid;
|
||||
|
||||
/// <summary>
|
||||
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
|
||||
/// </summary>
|
||||
public bool DifferentValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FlaxObjectRefPickerControl"/> class.
|
||||
/// </summary>
|
||||
@@ -154,7 +166,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Value = actor;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
}, PresenterContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -163,7 +175,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Value = script;
|
||||
RootWindow.Focus();
|
||||
Focus();
|
||||
});
|
||||
}, PresenterContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +209,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal);
|
||||
|
||||
// Check if has item selected
|
||||
if (isSelected)
|
||||
if (DifferentValues)
|
||||
{
|
||||
// Draw info
|
||||
Render2D.PushClip(nameRect);
|
||||
Render2D.DrawText(style.FontMedium, Type != null ? $"Multiple Values ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? style.ForegroundGrey : style.ForegroundGrey.AlphaMultiplied(0.75f), TextAlignment.Near, TextAlignment.Center);
|
||||
Render2D.PopClip();
|
||||
}
|
||||
else if (isSelected)
|
||||
{
|
||||
// Draw name
|
||||
Render2D.PushClip(nameRect);
|
||||
@@ -326,10 +345,19 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode;
|
||||
_linkedTreeNode.ExpandAllParents();
|
||||
Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true);
|
||||
_linkedTreeNode.StartHighlight();
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
_linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode;
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
_linkedTreeNode = prefabWindow.Graph.Root.Find(actor).TreeNode;
|
||||
if (_linkedTreeNode != null)
|
||||
{
|
||||
_linkedTreeNode.ExpandAllParents();
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
(prefabWindow.Tree.Parent as Panel).ScrollViewTo(_linkedTreeNode, true);
|
||||
_linkedTreeNode.StartHighlight();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -372,9 +400,20 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Select object
|
||||
if (_value is Actor actor)
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
{
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
prefabWindow.Select(prefabWindow.Graph.Root.Find(actor));
|
||||
}
|
||||
else if (_value is Script script && script.Actor)
|
||||
Editor.Instance.SceneEditing.Select(script.Actor);
|
||||
{
|
||||
var a = script.Actor;
|
||||
if (PresenterContext is PropertiesWindow)
|
||||
Editor.Instance.SceneEditing.Select(a);
|
||||
else if (PresenterContext is PrefabWindow prefabWindow)
|
||||
prefabWindow.Select(prefabWindow.Graph.Root.Find(a));
|
||||
}
|
||||
else if (_value is Asset asset)
|
||||
Editor.Instance.Windows.ContentWin.Select(asset);
|
||||
}
|
||||
@@ -415,13 +454,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Ensure to have valid drag helpers (uses lazy init)
|
||||
if (_dragActors == null)
|
||||
_dragActors = new DragActors(x => IsValid(x.Actor));
|
||||
_dragActors = new DragActors(ValidateDragActor);
|
||||
if (_dragActorsWithScript == null)
|
||||
_dragActorsWithScript = new DragActors(ValidateDragActorWithScript);
|
||||
if (_dragAssets == null)
|
||||
_dragAssets = new DragAssets(ValidateDragAsset);
|
||||
if (_dragScripts == null)
|
||||
_dragScripts = new DragScripts(IsValid);
|
||||
_dragScripts = new DragScripts(ValidateDragScript);
|
||||
if (_dragHandlers == null)
|
||||
{
|
||||
_dragHandlers = new DragHandlers
|
||||
@@ -446,6 +485,43 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return DragEffect;
|
||||
}
|
||||
|
||||
private bool ValidateDragActor(ActorNode a)
|
||||
{
|
||||
if (!IsValid(a.Actor))
|
||||
return false;
|
||||
|
||||
if (PresenterContext is PrefabWindow prefabWindow)
|
||||
{
|
||||
if (prefabWindow.Tree == a.TreeNode.ParentTree)
|
||||
return true;
|
||||
}
|
||||
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||
{
|
||||
if (a.ParentScene != null)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ValidateDragScript(Script script)
|
||||
{
|
||||
if (!IsValid(script))
|
||||
return false;
|
||||
|
||||
if (PresenterContext is PrefabWindow prefabWindow)
|
||||
{
|
||||
var actorNode = prefabWindow.Graph.Root.Find(script.Actor);
|
||||
if (actorNode != null)
|
||||
return true;
|
||||
}
|
||||
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||
{
|
||||
if (script.Actor.HasScene)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ValidateDragAsset(AssetItem assetItem)
|
||||
{
|
||||
// Check if can accept assets
|
||||
@@ -464,7 +540,18 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
private bool ValidateDragActorWithScript(ActorNode node)
|
||||
{
|
||||
return node.Actor.Scripts.Any(IsValid);
|
||||
bool isCorrectContext = false;
|
||||
if (PresenterContext is PrefabWindow prefabWindow)
|
||||
{
|
||||
if (prefabWindow.Tree == node.TreeNode.ParentTree)
|
||||
isCorrectContext = true;
|
||||
}
|
||||
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||
{
|
||||
if (node.ParentScene != null)
|
||||
isCorrectContext = true;
|
||||
}
|
||||
return node.Actor.Scripts.Any(IsValid) && isCorrectContext;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -536,6 +623,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (!HasDifferentTypes)
|
||||
{
|
||||
_element = layout.Custom<FlaxObjectRefPickerControl>();
|
||||
_element.CustomControl.PresenterContext = Presenter.Owner;
|
||||
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
|
||||
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
|
||||
}
|
||||
@@ -546,7 +634,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (!HasDifferentValues)
|
||||
var differentValues = HasDifferentValues;
|
||||
_element.CustomControl.DifferentValues = differentValues;
|
||||
if (!differentValues)
|
||||
{
|
||||
_element.CustomControl.Value = Values[0] as Object;
|
||||
}
|
||||
|
||||
@@ -819,6 +819,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
OnGroupsEnd();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_visibleIfCaches = null;
|
||||
_visibleIfPropertiesListsCache = null;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
|
||||
@@ -228,7 +228,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Handle Sliding
|
||||
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
||||
{
|
||||
// TODO: handle linked values
|
||||
Float3 average = Float3.Zero;
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
@@ -251,12 +250,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
var v = Values[i];
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
if (LinkValues)
|
||||
{
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(newValue.X, newValue.Y, newValue.Z);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3(newValue.X, newValue.Y, newValue.Z);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(newValue.X, newValue.Y, newValue.Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
@@ -267,16 +278,27 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: handle linked values
|
||||
for (int i = 0; i < Values.Count; i++)
|
||||
{
|
||||
object v = Values[i];
|
||||
if (v is Vector3 asVector3)
|
||||
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
|
||||
if (LinkValues)
|
||||
{
|
||||
if (v is Vector3 asVector3)
|
||||
v = asVector3 + new Vector3(xValue, yValue, zValue);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = asFloat3 + new Float3(xValue, yValue, zValue);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = asDouble3 + new Double3(xValue, yValue, zValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v is Vector3 asVector3)
|
||||
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
|
||||
else if (v is Float3 asFloat3)
|
||||
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
|
||||
else if (v is Double3 asDouble3)
|
||||
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
|
||||
}
|
||||
|
||||
newObjects[i] = v;
|
||||
}
|
||||
|
||||
@@ -96,6 +96,20 @@ namespace FlaxEditor.CustomEditors
|
||||
menu.Show(groupPanel, location);
|
||||
}
|
||||
|
||||
internal string GetLayoutCachePath(string name)
|
||||
{
|
||||
// Build group identifier (made of path from group titles)
|
||||
var expandPath = name;
|
||||
var container = this;
|
||||
while (container != null && !(container is CustomEditorPresenter))
|
||||
{
|
||||
if (container.ContainerControl is DropPanel dropPanel)
|
||||
expandPath = dropPanel.HeaderText + "/" + expandPath;
|
||||
container = container._parent;
|
||||
}
|
||||
return expandPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds new group element.
|
||||
/// </summary>
|
||||
@@ -112,14 +126,7 @@ namespace FlaxEditor.CustomEditors
|
||||
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||
{
|
||||
// Build group identifier (made of path from group titles)
|
||||
var expandPath = title;
|
||||
var container = this;
|
||||
while (container != null && !(container is CustomEditorPresenter))
|
||||
{
|
||||
if (container.ContainerControl is DropPanel dropPanel)
|
||||
expandPath = dropPanel.HeaderText + "/" + expandPath;
|
||||
container = container._parent;
|
||||
}
|
||||
var expandPath = GetLayoutCachePath(title);
|
||||
|
||||
// Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression)
|
||||
if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup)
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace FlaxEditor.CustomEditors
|
||||
if (objA == null && objB is string objBStr && objBStr.Length == 0)
|
||||
return true;
|
||||
|
||||
return Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals(objA, objB);
|
||||
return FlaxEngine.Json.JsonSerializer.ValueEquals(objA, objB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -550,7 +550,7 @@ int32 Editor::LoadProduct()
|
||||
}
|
||||
if (!FileSystem::FileExists(files[0]))
|
||||
{
|
||||
Platform::Fatal(TEXT("Cannot opoen selected project file because it doesn't exist."));
|
||||
Platform::Fatal(TEXT("Cannot open selected project file because it doesn't exist."));
|
||||
return -1;
|
||||
}
|
||||
projectPath = StringUtils::GetDirectoryName(files[0]);
|
||||
|
||||
@@ -1686,9 +1686,6 @@ namespace FlaxEditor
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetPrefabNestedObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial void Internal_GetPrefabNestedObject(IntPtr prefabId, IntPtr prefabObjectId, IntPtr outPrefabId, IntPtr outPrefabObjectId);
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||
|
||||
|
||||
@@ -48,6 +48,11 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public bool CanEdit = true;
|
||||
|
||||
/// <summary>
|
||||
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
|
||||
/// </summary>
|
||||
public bool DifferentValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetPicker"/> class.
|
||||
/// </summary>
|
||||
@@ -121,7 +126,13 @@ namespace FlaxEditor.GUI
|
||||
if (CanEdit)
|
||||
Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
if (Validator.SelectedItem != null)
|
||||
if (DifferentValues)
|
||||
{
|
||||
// No element selected
|
||||
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
|
||||
Render2D.DrawText(style.FontMedium, "Multiple\nValues", iconRect, style.Foreground, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||
}
|
||||
else if (Validator.SelectedItem != null)
|
||||
{
|
||||
// Draw item preview
|
||||
Validator.SelectedItem.DrawThumbnail(ref iconRect);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
#define USE_IS_FOREGROUND
|
||||
#else
|
||||
#endif
|
||||
#if PLATFORM_SDL
|
||||
#define USE_SDL_WORKAROUNDS
|
||||
#endif
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -111,7 +114,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the empty menu popup o na screen.
|
||||
/// Shows the empty menu popup on a screen.
|
||||
/// </summary>
|
||||
/// <param name="control">The target control.</param>
|
||||
/// <param name="area">The target control area to cover.</param>
|
||||
@@ -215,21 +218,27 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
desc.AllowMaximize = false;
|
||||
desc.AllowDragAndDrop = false;
|
||||
desc.IsTopmost = true;
|
||||
desc.IsRegularWindow = false;
|
||||
desc.Type = WindowType.Popup;
|
||||
desc.Parent = parentWin.Window;
|
||||
desc.Title = "ContextMenu";
|
||||
desc.HasSizingFrame = false;
|
||||
OnWindowCreating(ref desc);
|
||||
_window = Platform.CreateWindow(ref desc);
|
||||
_window.GotFocus += OnWindowGotFocus;
|
||||
_window.LostFocus += OnWindowLostFocus;
|
||||
|
||||
#if USE_IS_FOREGROUND && USE_SDL_WORKAROUNDS
|
||||
// The focus between popup and parent windows doesn't change, force hide the popup when clicked on parent
|
||||
parentWin.Window.MouseDown += OnWindowMouseDown;
|
||||
_window.Closed += () => parentWin.Window.MouseDown -= OnWindowMouseDown;
|
||||
#endif
|
||||
|
||||
// Attach to the window
|
||||
_parentCM = parent as ContextMenuBase;
|
||||
Parent = _window.GUI;
|
||||
|
||||
// Show
|
||||
Visible = true;
|
||||
if (_window == null)
|
||||
return;
|
||||
_window.Show();
|
||||
PerformLayout();
|
||||
_previouslyFocused = parentWin.FocusedControl;
|
||||
@@ -378,6 +387,17 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
private void OnWindowGotFocus()
|
||||
{
|
||||
}
|
||||
|
||||
private void OnWindowMouseDown(ref Float2 mousePosition, MouseButton button, ref bool handled)
|
||||
{
|
||||
// The user clicked outside the popup window
|
||||
Hide();
|
||||
}
|
||||
#else
|
||||
private void OnWindowGotFocus()
|
||||
{
|
||||
var child = _childCM;
|
||||
@@ -391,6 +411,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnWindowLostFocus()
|
||||
{
|
||||
@@ -489,7 +510,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Let root context menu to check if none of the popup windows
|
||||
if (_parentCM == null && !IsForeground)
|
||||
{
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
if (!IsMouseOver)
|
||||
Hide();
|
||||
#else
|
||||
Hide();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,10 @@ namespace FlaxEditor.GUI
|
||||
internal bool _isMovingTangent;
|
||||
internal bool _movedView;
|
||||
internal bool _movedKeyframes;
|
||||
internal bool _toggledSelection;
|
||||
private TangentPoint _movingTangent;
|
||||
private Float2 _movingSelectionStart;
|
||||
private Float2 _movingSelectionStartPosLock;
|
||||
private Float2[] _movingSelectionOffsets;
|
||||
private Float2 _cmShowPos;
|
||||
|
||||
@@ -56,12 +58,11 @@ namespace FlaxEditor.GUI
|
||||
internal void UpdateSelection(ref Rectangle selectionRect)
|
||||
{
|
||||
// Find controls to select
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
var children = _children;
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
if (Children[i] is KeyframePoint p)
|
||||
{
|
||||
if (children[i] is KeyframePoint p)
|
||||
p.IsSelected = p.Bounds.Intersects(ref selectionRect);
|
||||
}
|
||||
}
|
||||
_editor.UpdateTangents();
|
||||
}
|
||||
@@ -72,6 +73,7 @@ namespace FlaxEditor.GUI
|
||||
_isMovingSelection = true;
|
||||
_movedKeyframes = false;
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
_movingSelectionStartPosLock = location;
|
||||
_movingSelectionStart = PointToKeyframes(location, ref viewRect);
|
||||
if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count)
|
||||
_movingSelectionOffsets = new Float2[_editor._points.Count];
|
||||
@@ -82,10 +84,17 @@ namespace FlaxEditor.GUI
|
||||
|
||||
internal void OnMove(Float2 location)
|
||||
{
|
||||
// Skip updating keyframes until move actual starts to be meaningful
|
||||
if (Float2.Distance(ref _movingSelectionStartPosLock, ref location) < 1.5f)
|
||||
return;
|
||||
_movingSelectionStartPosLock = Float2.Minimum;
|
||||
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
var locationKeyframes = PointToKeyframes(location, ref viewRect);
|
||||
var accessor = _editor.Accessor;
|
||||
var components = accessor.GetCurveComponents();
|
||||
var snapEnabled = Root.GetKey(KeyboardKeys.Control);
|
||||
var snapGrid = snapEnabled ? _editor.GetGridSnap() : Float2.One;
|
||||
for (var i = 0; i < _editor._points.Count; i++)
|
||||
{
|
||||
var p = _editor._points[i];
|
||||
@@ -122,7 +131,20 @@ namespace FlaxEditor.GUI
|
||||
if (isFirstSelected)
|
||||
{
|
||||
time = locationKeyframes.X + offset.X;
|
||||
}
|
||||
|
||||
if (snapEnabled)
|
||||
{
|
||||
// Snap to the grid
|
||||
var key = new Float2(time, value);
|
||||
key = Float2.SnapToGrid(key, snapGrid);
|
||||
time = key.X;
|
||||
value = key.Y;
|
||||
}
|
||||
|
||||
// Clamp and snap time to the valid range
|
||||
if (isFirstSelected)
|
||||
{
|
||||
if (_editor.FPS.HasValue)
|
||||
{
|
||||
float fps = _editor.FPS.Value;
|
||||
@@ -131,8 +153,6 @@ namespace FlaxEditor.GUI
|
||||
time = Mathf.Clamp(time, minTime, maxTime);
|
||||
}
|
||||
|
||||
// TODO: snapping keyframes to grid when moving
|
||||
|
||||
_editor.SetKeyframeInternal(p.Index, time, value, p.Component);
|
||||
}
|
||||
_editor.UpdateKeyframes();
|
||||
@@ -234,7 +254,11 @@ namespace FlaxEditor.GUI
|
||||
var k = _editor.GetKeyframe(_movingTangent.Index);
|
||||
var kv = _editor.GetKeyframeValue(k);
|
||||
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
|
||||
_movingTangent.TangentValue = PointToKeyframes(location, ref viewRect).Y - value;
|
||||
var tangent = PointToKeyframes(location, ref viewRect).Y - value;
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
tangent = Float2.SnapToGrid(new Float2(0, tangent), _editor.GetGridSnap()).Y; // Snap tangent over Y axis
|
||||
tangent = tangent * _editor.ViewScale.X * 2;
|
||||
_movingTangent.TangentValue = tangent;
|
||||
_editor.UpdateTangents();
|
||||
Cursor = CursorType.SizeNS;
|
||||
_movedKeyframes = true;
|
||||
@@ -283,6 +307,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
|
||||
// Cache data
|
||||
_toggledSelection = false;
|
||||
_isMovingSelection = false;
|
||||
_isMovingTangent = false;
|
||||
_mousePos = location;
|
||||
@@ -305,13 +330,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
if (_leftMouseDown)
|
||||
{
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
// Toggle selection
|
||||
keyframe.IsSelected = !keyframe.IsSelected;
|
||||
_editor.UpdateTangents();
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Shift))
|
||||
if (Root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
// Select range
|
||||
keyframe.IsSelected = true;
|
||||
@@ -335,10 +354,14 @@ namespace FlaxEditor.GUI
|
||||
else if (!keyframe.IsSelected)
|
||||
{
|
||||
// Select node
|
||||
if (_editor.KeyframesEditorContext != null)
|
||||
_editor.KeyframesEditorContext.OnKeyframesDeselect(_editor);
|
||||
else
|
||||
_editor.ClearSelection();
|
||||
if (!Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
if (_editor.KeyframesEditorContext != null)
|
||||
_editor.KeyframesEditorContext.OnKeyframesDeselect(_editor);
|
||||
else
|
||||
_editor.ClearSelection();
|
||||
}
|
||||
_toggledSelection = true;
|
||||
keyframe.IsSelected = true;
|
||||
_editor.UpdateTangents();
|
||||
}
|
||||
@@ -429,6 +452,12 @@ namespace FlaxEditor.GUI
|
||||
else
|
||||
OnMoveEnd(location);
|
||||
}
|
||||
// Toggle selection
|
||||
else if (!_toggledSelection && Root.GetKey(KeyboardKeys.Control) && GetChildAt(location) is KeyframePoint keyframe)
|
||||
{
|
||||
keyframe.IsSelected = !keyframe.IsSelected;
|
||||
_editor.UpdateTangents();
|
||||
}
|
||||
|
||||
_isMovingSelection = false;
|
||||
_isMovingTangent = false;
|
||||
@@ -514,11 +543,11 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
if (base.OnMouseDoubleClick(location, button))
|
||||
return true;
|
||||
|
||||
|
||||
// Add keyframe on double click
|
||||
var child = GetChildAt(location);
|
||||
if (child is not KeyframePoint &&
|
||||
child is not TangentPoint &&
|
||||
if (child is not KeyframePoint &&
|
||||
child is not TangentPoint &&
|
||||
_editor.KeyframesCount < _editor.MaxKeyframes)
|
||||
{
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
@@ -545,7 +574,7 @@ namespace FlaxEditor.GUI
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
var locationInKeyframes = PointToKeyframes(location, ref viewRect);
|
||||
var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
|
||||
|
||||
|
||||
// Scale relative to the curve size
|
||||
var scale = new Float2(delta * 0.1f);
|
||||
_editor._mainPanel.GetDesireClientArea(out var mainPanelArea);
|
||||
|
||||
@@ -163,10 +163,11 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Style.Current;
|
||||
var rect = new Rectangle(Float2.Zero, Size);
|
||||
var color = Editor.ShowCollapsed ? Color.Gray : Editor.Colors[Component];
|
||||
var color = Editor.ShowCollapsed ? style.ForegroundDisabled : Editor.Colors[Component];
|
||||
if (IsSelected)
|
||||
color = Editor.ContainsFocus ? Color.YellowGreen : Color.Lerp(Color.Gray, Color.YellowGreen, 0.4f);
|
||||
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
|
||||
if (IsMouseOver)
|
||||
color *= 1.1f;
|
||||
Render2D.FillRectangle(rect, color);
|
||||
@@ -244,14 +245,19 @@ namespace FlaxEditor.GUI
|
||||
set => Editor.SetKeyframeTangentInternal(Index, IsIn, Component, value);
|
||||
}
|
||||
|
||||
internal float TangentOffset => 50.0f / Editor.ViewScale.X;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Style.Current;
|
||||
var thickness = 6.0f / Mathf.Max(Editor.ViewScale.X, 1.0f);
|
||||
var size = Size;
|
||||
var pointPos = PointFromParent(Point.Center);
|
||||
Render2D.DrawLine(Size * 0.5f, pointPos, Color.Gray);
|
||||
Render2D.DrawLine(size * 0.5f, pointPos, style.ForegroundDisabled, thickness);
|
||||
|
||||
var rect = new Rectangle(Float2.Zero, Size);
|
||||
var color = Color.MediumVioletRed;
|
||||
var rect = new Rectangle(Float2.Zero, size);
|
||||
var color = style.BorderSelected;
|
||||
if (IsMouseOver)
|
||||
color *= 1.1f;
|
||||
Render2D.FillRectangle(rect, color);
|
||||
@@ -289,7 +295,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The curve time/value axes tick steps.
|
||||
/// </summary>
|
||||
protected float[] TickSteps = Utilities.Utils.CurveTickSteps;
|
||||
protected double[] TickSteps = Utilities.Utils.CurveTickSteps;
|
||||
|
||||
/// <summary>
|
||||
/// The curve contents area.
|
||||
@@ -442,7 +448,7 @@ namespace FlaxEditor.GUI
|
||||
_mainPanel = new Panel(ScrollBars.Both)
|
||||
{
|
||||
ScrollMargin = new Margin(150.0f),
|
||||
AlwaysShowScrollbars = true,
|
||||
AlwaysShowScrollbars = false,
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = Margin.Zero,
|
||||
Parent = this
|
||||
@@ -668,26 +674,82 @@ namespace FlaxEditor.GUI
|
||||
OnEditingEnd();
|
||||
}
|
||||
|
||||
private void ShowCurve(bool selectedOnly)
|
||||
{
|
||||
if (_points.Count == 0)
|
||||
return;
|
||||
int pass = 1;
|
||||
REDO:
|
||||
|
||||
// Get curve bounds in Keyframes (time and value)
|
||||
Float2 posMin = Float2.Maximum, posMax = Float2.Minimum;
|
||||
// TODO: include bezier curve bounds calculation to handle curve outside the bounds made out of points
|
||||
foreach (var point in _points)
|
||||
{
|
||||
if (selectedOnly && !point.IsSelected)
|
||||
continue;
|
||||
var pos = point.Point;
|
||||
Float2.Min(ref posMin, ref pos, out posMin);
|
||||
Float2.Max(ref posMax, ref pos, out posMax);
|
||||
}
|
||||
|
||||
// Apply margin around the area
|
||||
var posMargin = (posMax - posMin) * 0.05f;
|
||||
posMin -= posMargin;
|
||||
posMax += posMargin;
|
||||
|
||||
// Convert from Keyframes to Contents
|
||||
_mainPanel.GetDesireClientArea(out var viewRect);
|
||||
PointFromKeyframesToContents(ref posMin, ref viewRect);
|
||||
PointFromKeyframesToContents(ref posMax, ref viewRect);
|
||||
var tmp = posMin;
|
||||
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||
var contentsSize = posMax - posMin;
|
||||
|
||||
// Convert from Contents to Main Panel
|
||||
posMin = _contents.PointToParent(posMin);
|
||||
posMax = _contents.PointToParent(posMax);
|
||||
tmp = posMin;
|
||||
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||
|
||||
// Update zoom (leave unchanged when focusing a single point)
|
||||
var zoomMask = EnableZoom;
|
||||
if (Mathf.IsZero(posMargin.X))
|
||||
zoomMask &= ~UseMode.Horizontal;
|
||||
if (Mathf.IsZero(posMargin.Y))
|
||||
zoomMask &= ~UseMode.Vertical;
|
||||
ViewScale = ApplyUseModeMask(zoomMask, viewRect.Size / contentsSize, ViewScale);
|
||||
|
||||
// Update scroll (attempt to center the area when it's smaller than the view)
|
||||
Float2 viewOffset = -posMin;
|
||||
Float2 viewSize = _mainPanel.Size;
|
||||
Float2 viewSizeLeft = viewSize - Float2.Clamp(posMax - posMin, Float2.Zero, viewSize);
|
||||
viewOffset += viewSizeLeft * 0.5f;
|
||||
viewOffset = ApplyUseModeMask(EnablePanning, viewOffset, _mainPanel.ViewOffset);
|
||||
_mainPanel.ViewOffset = viewOffset;
|
||||
|
||||
// Do it multiple times so the view offset can be properly calculate once the view scale gets changes
|
||||
if (pass++ <= 2)
|
||||
goto REDO;
|
||||
|
||||
UpdateKeyframes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the view on the selected keyframes.
|
||||
/// </summary>
|
||||
public void FocusSelection()
|
||||
{
|
||||
// Fallback to showing whole curve if nothing is selected
|
||||
ShowCurve(SelectionCount != 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ShowWholeCurve()
|
||||
{
|
||||
_mainPanel.GetDesireClientArea(out var mainPanelArea);
|
||||
ViewScale = ApplyUseModeMask(EnableZoom, mainPanelArea.Size / _contents.Size, ViewScale);
|
||||
Float2 minPos = Float2.Maximum;
|
||||
foreach (var point in _points)
|
||||
{
|
||||
var pos = point.PointToParent(point.Location);
|
||||
Float2.Min(ref minPos, ref pos, out minPos);
|
||||
}
|
||||
var minPosPoint = _contents.PointToParent(ref minPos);
|
||||
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
|
||||
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
|
||||
if (_mainPanel.HScrollBar != null)
|
||||
_mainPanel.HScrollBar.TargetValue = scroll.X;
|
||||
if (_mainPanel.VScrollBar != null)
|
||||
_mainPanel.VScrollBar.TargetValue = scroll.Y;
|
||||
|
||||
UpdateKeyframes();
|
||||
ShowCurve(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -766,10 +828,7 @@ namespace FlaxEditor.GUI
|
||||
point = _contents.PointFromParent(point);
|
||||
|
||||
// Contents -> Keyframes
|
||||
return new Float2(
|
||||
(point.X + _contents.Location.X) / UnitsPerSecond,
|
||||
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
||||
);
|
||||
return PointFromContentsToKeyframes(ref point, ref curveContentAreaBounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -781,10 +840,7 @@ namespace FlaxEditor.GUI
|
||||
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
|
||||
{
|
||||
// Keyframes -> Contents
|
||||
point = new Float2(
|
||||
point.X * UnitsPerSecond - _contents.Location.X,
|
||||
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
||||
);
|
||||
PointFromKeyframesToContents(ref point, ref curveContentAreaBounds);
|
||||
|
||||
// Contents -> Main Panel
|
||||
point = _contents.PointToParent(point);
|
||||
@@ -793,11 +849,27 @@ namespace FlaxEditor.GUI
|
||||
return _mainPanel.PointToParent(point);
|
||||
}
|
||||
|
||||
internal Float2 PointFromContentsToKeyframes(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||
{
|
||||
return new Float2(
|
||||
(point.X + _contents.Location.X) / UnitsPerSecond,
|
||||
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
||||
);
|
||||
}
|
||||
|
||||
internal void PointFromKeyframesToContents(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||
{
|
||||
point = new Float2(
|
||||
point.X * UnitsPerSecond - _contents.Location.X,
|
||||
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
||||
);
|
||||
}
|
||||
|
||||
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
|
||||
{
|
||||
Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
||||
Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||
{
|
||||
var p = PointFromKeyframes(axis * tick, ref viewRect);
|
||||
var p = PointFromKeyframes(axis * (float)tick, ref viewRect);
|
||||
|
||||
// Draw line
|
||||
var lineRect = new Rectangle
|
||||
@@ -820,6 +892,24 @@ namespace FlaxEditor.GUI
|
||||
}, TickSteps, ref _tickStrengths, min, max, pixelRange);
|
||||
}
|
||||
|
||||
private void SetupGrid(out Float2 min, out Float2 max, out Float2 pixelRange)
|
||||
{
|
||||
var viewRect = _mainPanel.GetClientArea();
|
||||
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect);
|
||||
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
|
||||
|
||||
min = Float2.Min(upperLeft, bottomRight);
|
||||
max = Float2.Max(upperLeft, bottomRight);
|
||||
pixelRange = (max - min) * ViewScale * UnitsPerSecond;
|
||||
}
|
||||
|
||||
private Float2 GetGridSnap()
|
||||
{
|
||||
SetupGrid(out var min, out var max, out var pixelRange);
|
||||
return new Float2(Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.X, max.X, pixelRange.X),
|
||||
Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.Y, max.Y, pixelRange.Y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the curve.
|
||||
/// </summary>
|
||||
@@ -849,12 +939,7 @@ namespace FlaxEditor.GUI
|
||||
// Draw time and values axes
|
||||
if (ShowAxes != UseMode.Off)
|
||||
{
|
||||
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect);
|
||||
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
|
||||
|
||||
var min = Float2.Min(upperLeft, bottomRight);
|
||||
var max = Float2.Max(upperLeft, bottomRight);
|
||||
var pixelRange = (max - min) * ViewScale * UnitsPerSecond;
|
||||
SetupGrid(out var min, out var max, out var pixelRange);
|
||||
|
||||
Render2D.PushClip(ref viewRect);
|
||||
|
||||
@@ -939,7 +1024,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
else if (options.FocusSelection.Process(this))
|
||||
{
|
||||
ShowWholeCurve();
|
||||
FocusSelection();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2200,7 +2285,7 @@ namespace FlaxEditor.GUI
|
||||
|
||||
var tangent = t.TangentValue;
|
||||
var direction = t.IsIn ? -1.0f : 1.0f;
|
||||
var offset = 30.0f;
|
||||
var offset = t.TangentOffset;
|
||||
var location = GetKeyframePoint(ref k, selectedComponent);
|
||||
t.Size = KeyframesSize / ViewScale;
|
||||
t.Location = new Float2
|
||||
@@ -2227,6 +2312,18 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SetScaleInternal(ref Float2 scale)
|
||||
{
|
||||
base.SetScaleInternal(ref scale);
|
||||
|
||||
if (!_showCollapsed)
|
||||
{
|
||||
// Refresh keyframes when zooming (their size depends on the scale)
|
||||
UpdateKeyframes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnShowContextMenu(ContextMenu.ContextMenu cm, int selectionCount)
|
||||
{
|
||||
|
||||
@@ -1,529 +0,0 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class used to handle docking windows dragging and docking.
|
||||
/// </summary>
|
||||
public class DockHintWindow
|
||||
{
|
||||
private FloatWindowDockPanel _toMove;
|
||||
|
||||
private Float2 _dragOffset;
|
||||
private Float2 _defaultWindowSize;
|
||||
private Rectangle _rectDock;
|
||||
private Rectangle _rectWindow;
|
||||
private Float2 _mouse;
|
||||
private DockState _toSet;
|
||||
private DockPanel _toDock;
|
||||
private bool _lateDragOffsetUpdate;
|
||||
|
||||
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
|
||||
|
||||
private DockHintWindow(FloatWindowDockPanel toMove)
|
||||
{
|
||||
_toMove = toMove;
|
||||
_toSet = DockState.Float;
|
||||
var window = toMove.Window.Window;
|
||||
|
||||
// Remove focus from drag target
|
||||
_toMove.Focus();
|
||||
_toMove.Defocus();
|
||||
|
||||
// Focus window
|
||||
window.Focus();
|
||||
|
||||
// Check if window is maximized and restore window.
|
||||
if (window.IsMaximized)
|
||||
{
|
||||
// Restore window and set position to mouse.
|
||||
var mousePos = window.MousePosition;
|
||||
var previousSize = window.Size;
|
||||
window.Restore();
|
||||
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
|
||||
}
|
||||
|
||||
// Calculate dragging offset and move window to the destination position
|
||||
var mouseScreenPosition = Platform.MousePosition;
|
||||
|
||||
// If the _toMove window was not focused when initializing this window, the result vector only contains zeros
|
||||
// and to prevent a failure, we need to perform an update for the drag offset at later time which will be done in the OnMouseMove event handler.
|
||||
if (mouseScreenPosition != Float2.Zero)
|
||||
CalculateDragOffset(mouseScreenPosition);
|
||||
else
|
||||
_lateDragOffsetUpdate = true;
|
||||
|
||||
// Get initial size
|
||||
_defaultWindowSize = window.Size;
|
||||
|
||||
// Init proxy window
|
||||
Proxy.Init(ref _defaultWindowSize);
|
||||
|
||||
// Bind events
|
||||
Proxy.Window.MouseUp += OnMouseUp;
|
||||
Proxy.Window.MouseMove += OnMouseMove;
|
||||
Proxy.Window.LostFocus += OnLostFocus;
|
||||
|
||||
// Start tracking mouse
|
||||
Proxy.Window.StartTrackingMouse(false);
|
||||
|
||||
// Update window GUI
|
||||
Proxy.Window.GUI.PerformLayout();
|
||||
|
||||
// Update rectangles
|
||||
UpdateRects();
|
||||
|
||||
// Hide base window
|
||||
window.Hide();
|
||||
|
||||
// Enable hit window presentation
|
||||
Proxy.Window.RenderingEnabled = true;
|
||||
Proxy.Window.Show();
|
||||
Proxy.Window.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// End tracking mouse
|
||||
Proxy.Window.EndTrackingMouse();
|
||||
|
||||
// Disable rendering
|
||||
Proxy.Window.RenderingEnabled = false;
|
||||
|
||||
// Unbind events
|
||||
Proxy.Window.MouseUp -= OnMouseUp;
|
||||
Proxy.Window.MouseMove -= OnMouseMove;
|
||||
Proxy.Window.LostFocus -= OnLostFocus;
|
||||
|
||||
// Hide the proxy
|
||||
Proxy.Hide();
|
||||
|
||||
if (_toMove == null)
|
||||
return;
|
||||
|
||||
// Check if window won't be docked
|
||||
if (_toSet == DockState.Float)
|
||||
{
|
||||
var window = _toMove.Window?.Window;
|
||||
if (window == null)
|
||||
return;
|
||||
var mouse = Platform.MousePosition;
|
||||
|
||||
// Move base window
|
||||
window.Position = mouse - _dragOffset;
|
||||
|
||||
// Show base window
|
||||
window.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
|
||||
|
||||
// Check if window has only single tab
|
||||
if (hasNoChildPanels && _toMove.TabsCount == 1)
|
||||
{
|
||||
// Dock window
|
||||
_toMove.GetTab(0).Show(_toSet, _toDock);
|
||||
}
|
||||
// Check if dock as tab and has no child panels
|
||||
else if (hasNoChildPanels && _toSet == DockState.DockFill)
|
||||
{
|
||||
// Dock all tabs
|
||||
while (_toMove.TabsCount > 0)
|
||||
{
|
||||
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedTab = _toMove.SelectedTab;
|
||||
|
||||
// Dock the first tab into the target location
|
||||
var firstTab = _toMove.GetTab(0);
|
||||
firstTab.Show(_toSet, _toDock);
|
||||
|
||||
// Dock rest of the tabs
|
||||
while (_toMove.TabsCount > 0)
|
||||
{
|
||||
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
|
||||
}
|
||||
|
||||
// Keep selected tab being selected
|
||||
selectedTab?.SelectTab();
|
||||
}
|
||||
|
||||
// Focus target window
|
||||
_toDock.Root.Focus();
|
||||
}
|
||||
|
||||
_toMove = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new dragging hit window.
|
||||
/// </summary>
|
||||
/// <param name="toMove">Floating dock panel to move.</param>
|
||||
/// <returns>The dock hint window object.</returns>
|
||||
public static DockHintWindow Create(FloatWindowDockPanel toMove)
|
||||
{
|
||||
if (toMove == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
return new DockHintWindow(toMove);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the new dragging hit window.
|
||||
/// </summary>
|
||||
/// <param name="toMove">Dock window to move.</param>
|
||||
/// <returns>The dock hint window object.</returns>
|
||||
public static DockHintWindow Create(DockWindow toMove)
|
||||
{
|
||||
if (toMove == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
// Show floating
|
||||
toMove.ShowFloating();
|
||||
|
||||
// Move window to the mouse position (with some offset for caption bar)
|
||||
var window = (WindowRootControl)toMove.Root;
|
||||
var mouse = Platform.MousePosition;
|
||||
window.Window.Position = mouse - new Float2(8, 8);
|
||||
|
||||
// Get floating panel
|
||||
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
|
||||
|
||||
return new DockHintWindow(floatingPanelToMove);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates window rectangle in the dock window.
|
||||
/// </summary>
|
||||
/// <param name="state">Window dock state.</param>
|
||||
/// <param name="rect">Dock panel rectangle.</param>
|
||||
/// <returns>Calculated window rectangle.</returns>
|
||||
public static Rectangle CalculateDockRect(DockState state, ref Rectangle rect)
|
||||
{
|
||||
Rectangle result = rect;
|
||||
switch (state)
|
||||
{
|
||||
case DockState.DockFill:
|
||||
result.Location.Y += DockPanel.DefaultHeaderHeight;
|
||||
result.Size.Y -= DockPanel.DefaultHeaderHeight;
|
||||
break;
|
||||
case DockState.DockTop:
|
||||
result.Size.Y *= DockPanel.DefaultSplitterValue;
|
||||
break;
|
||||
case DockState.DockLeft:
|
||||
result.Size.X *= DockPanel.DefaultSplitterValue;
|
||||
break;
|
||||
case DockState.DockBottom:
|
||||
result.Location.Y += result.Size.Y * (1 - DockPanel.DefaultSplitterValue);
|
||||
result.Size.Y *= DockPanel.DefaultSplitterValue;
|
||||
break;
|
||||
case DockState.DockRight:
|
||||
result.Location.X += result.Size.X * (1 - DockPanel.DefaultSplitterValue);
|
||||
result.Size.X *= DockPanel.DefaultSplitterValue;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void CalculateDragOffset(Float2 mouseScreenPosition)
|
||||
{
|
||||
var baseWinPos = _toMove.Window.Window.Position;
|
||||
_dragOffset = mouseScreenPosition - baseWinPos;
|
||||
}
|
||||
|
||||
private void UpdateRects()
|
||||
{
|
||||
// Cache mouse position
|
||||
_mouse = Platform.MousePosition;
|
||||
|
||||
// Check intersection with any dock panel
|
||||
var uiMouse = _mouse;
|
||||
_toDock = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove);
|
||||
|
||||
// Check dock state to use
|
||||
bool showProxyHints = _toDock != null;
|
||||
bool showBorderHints = showProxyHints;
|
||||
bool showCenterHint = showProxyHints;
|
||||
if (showProxyHints)
|
||||
{
|
||||
// If moved window has not only tabs but also child panels disable docking as tab
|
||||
if (_toMove.ChildPanelsCount > 0)
|
||||
showCenterHint = false;
|
||||
|
||||
// Disable docking windows with one or more dock panels inside
|
||||
if (_toMove.ChildPanelsCount > 0)
|
||||
showBorderHints = false;
|
||||
|
||||
// Get dock area
|
||||
_rectDock = _toDock.DockAreaBounds;
|
||||
|
||||
// Cache dock rectangles
|
||||
var size = _rectDock.Size;
|
||||
var offset = _rectDock.Location;
|
||||
var borderMargin = 4.0f;
|
||||
var hintWindowsSize = Proxy.HintWindowsSize * Platform.DpiScale;
|
||||
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
||||
var centerX = size.X * 0.5f;
|
||||
var centerY = size.Y * 0.5f;
|
||||
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
|
||||
// Hit test
|
||||
DockState toSet = DockState.Float;
|
||||
if (showBorderHints)
|
||||
{
|
||||
if (_rUpper.Contains(_mouse))
|
||||
toSet = DockState.DockTop;
|
||||
else if (_rBottom.Contains(_mouse))
|
||||
toSet = DockState.DockBottom;
|
||||
else if (_rLeft.Contains(_mouse))
|
||||
toSet = DockState.DockLeft;
|
||||
else if (_rRight.Contains(_mouse))
|
||||
toSet = DockState.DockRight;
|
||||
}
|
||||
if (showCenterHint && _rCenter.Contains(_mouse))
|
||||
toSet = DockState.DockFill;
|
||||
_toSet = toSet;
|
||||
|
||||
// Show proxy hint windows
|
||||
Proxy.Down.Position = _rBottom.Location;
|
||||
Proxy.Left.Position = _rLeft.Location;
|
||||
Proxy.Right.Position = _rRight.Location;
|
||||
Proxy.Up.Position = _rUpper.Location;
|
||||
Proxy.Center.Position = _rCenter.Location;
|
||||
}
|
||||
else
|
||||
{
|
||||
_toSet = DockState.Float;
|
||||
}
|
||||
|
||||
// Update proxy hint windows visibility
|
||||
Proxy.Down.IsVisible = showProxyHints & showBorderHints;
|
||||
Proxy.Left.IsVisible = showProxyHints & showBorderHints;
|
||||
Proxy.Right.IsVisible = showProxyHints & showBorderHints;
|
||||
Proxy.Up.IsVisible = showProxyHints & showBorderHints;
|
||||
Proxy.Center.IsVisible = showProxyHints & showCenterHint;
|
||||
|
||||
// Calculate proxy/dock/window rectangles
|
||||
if (_toDock == null)
|
||||
{
|
||||
// Floating window over nothing
|
||||
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_toSet == DockState.Float)
|
||||
{
|
||||
// Floating window over dock panel
|
||||
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use only part of the dock panel to show hint
|
||||
_rectWindow = CalculateDockRect(_toSet, ref _rectDock);
|
||||
}
|
||||
}
|
||||
|
||||
// Update proxy window
|
||||
Proxy.Window.ClientBounds = _rectWindow;
|
||||
}
|
||||
|
||||
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseMove(ref Float2 mousePos)
|
||||
{
|
||||
// Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window
|
||||
if (_lateDragOffsetUpdate)
|
||||
{
|
||||
// Calculate dragging offset and move window to the destination position
|
||||
CalculateDragOffset(mousePos);
|
||||
|
||||
// Reset state
|
||||
_lateDragOffsetUpdate = false;
|
||||
}
|
||||
|
||||
UpdateRects();
|
||||
}
|
||||
|
||||
private void OnLostFocus()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains helper proxy windows shared across docking panels. They are used to visualize docking window locations.
|
||||
/// </summary>
|
||||
public static class Proxy
|
||||
{
|
||||
/// <summary>
|
||||
/// The drag proxy window.
|
||||
/// </summary>
|
||||
public static Window Window;
|
||||
|
||||
/// <summary>
|
||||
/// The left hint proxy window.
|
||||
/// </summary>
|
||||
public static Window Left;
|
||||
|
||||
/// <summary>
|
||||
/// The right hint proxy window.
|
||||
/// </summary>
|
||||
public static Window Right;
|
||||
|
||||
/// <summary>
|
||||
/// The up hint proxy window.
|
||||
/// </summary>
|
||||
public static Window Up;
|
||||
|
||||
/// <summary>
|
||||
/// The down hint proxy window.
|
||||
/// </summary>
|
||||
public static Window Down;
|
||||
|
||||
/// <summary>
|
||||
/// The center hint proxy window.
|
||||
/// </summary>
|
||||
public static Window Center;
|
||||
|
||||
/// <summary>
|
||||
/// The hint windows size.
|
||||
/// </summary>
|
||||
public const float HintWindowsSize = 32.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the hit proxy windows. Those windows are used to indicate drag target areas (left, right, top, bottom, etc.).
|
||||
/// </summary>
|
||||
public static void InitHitProxy()
|
||||
{
|
||||
CreateProxy(ref Left, "DockHint.Left");
|
||||
CreateProxy(ref Right, "DockHint.Right");
|
||||
CreateProxy(ref Up, "DockHint.Up");
|
||||
CreateProxy(ref Down, "DockHint.Down");
|
||||
CreateProxy(ref Center, "DockHint.Center");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the hint window.
|
||||
/// </summary>
|
||||
/// <param name="initSize">Initial size of the proxy window.</param>
|
||||
public static void Init(ref Float2 initSize)
|
||||
{
|
||||
if (Window == null)
|
||||
{
|
||||
var settings = CreateWindowSettings.Default;
|
||||
settings.Title = "DockHint.Window";
|
||||
settings.Size = initSize;
|
||||
settings.AllowInput = true;
|
||||
settings.AllowMaximize = false;
|
||||
settings.AllowMinimize = false;
|
||||
settings.HasBorder = false;
|
||||
settings.HasSizingFrame = false;
|
||||
settings.IsRegularWindow = false;
|
||||
settings.SupportsTransparency = true;
|
||||
settings.ShowInTaskbar = false;
|
||||
settings.ShowAfterFirstPaint = false;
|
||||
settings.IsTopmost = true;
|
||||
|
||||
Window = Platform.CreateWindow(ref settings);
|
||||
Window.Opacity = 0.6f;
|
||||
Window.GUI.BackgroundColor = Style.Current.DragWindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resize proxy
|
||||
Window.ClientSize = initSize;
|
||||
}
|
||||
|
||||
InitHitProxy();
|
||||
}
|
||||
|
||||
private static void CreateProxy(ref Window win, string name)
|
||||
{
|
||||
if (win != null)
|
||||
return;
|
||||
|
||||
var settings = CreateWindowSettings.Default;
|
||||
settings.Title = name;
|
||||
settings.Size = new Float2(HintWindowsSize * Platform.DpiScale);
|
||||
settings.AllowInput = false;
|
||||
settings.AllowMaximize = false;
|
||||
settings.AllowMinimize = false;
|
||||
settings.HasBorder = false;
|
||||
settings.HasSizingFrame = false;
|
||||
settings.IsRegularWindow = false;
|
||||
settings.SupportsTransparency = true;
|
||||
settings.ShowInTaskbar = false;
|
||||
settings.ActivateWhenFirstShown = false;
|
||||
settings.IsTopmost = true;
|
||||
settings.ShowAfterFirstPaint = false;
|
||||
|
||||
win = Platform.CreateWindow(ref settings);
|
||||
win.Opacity = 0.6f;
|
||||
win.GUI.BackgroundColor = Style.Current.DragWindow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides proxy windows.
|
||||
/// </summary>
|
||||
public static void Hide()
|
||||
{
|
||||
HideProxy(ref Window);
|
||||
HideProxy(ref Left);
|
||||
HideProxy(ref Right);
|
||||
HideProxy(ref Up);
|
||||
HideProxy(ref Down);
|
||||
HideProxy(ref Center);
|
||||
}
|
||||
|
||||
private static void HideProxy(ref Window win)
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
win.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases proxy data and windows.
|
||||
/// </summary>
|
||||
public static void Dispose()
|
||||
{
|
||||
DisposeProxy(ref Window);
|
||||
DisposeProxy(ref Left);
|
||||
DisposeProxy(ref Right);
|
||||
DisposeProxy(ref Up);
|
||||
DisposeProxy(ref Down);
|
||||
DisposeProxy(ref Center);
|
||||
}
|
||||
|
||||
private static void DisposeProxy(ref Window win)
|
||||
{
|
||||
if (win)
|
||||
{
|
||||
win.Close(ClosingReason.User);
|
||||
win = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,11 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// The mouse position.
|
||||
/// </summary>
|
||||
public Float2 MousePosition = Float2.Minimum;
|
||||
|
||||
/// <summary>
|
||||
/// The mouse position.
|
||||
/// </summary>
|
||||
public Float2 MouseStartPosition = Float2.Minimum;
|
||||
|
||||
/// <summary>
|
||||
/// The start drag asynchronous window.
|
||||
@@ -165,7 +170,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating)
|
||||
{
|
||||
// Create docking hint window but in an async manner
|
||||
DockHintWindow.Create(_panel as FloatWindowDockPanel);
|
||||
WindowDragHelper.StartDragging(_panel as FloatWindowDockPanel);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -176,7 +181,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
_panel.SelectTab(index - 1);
|
||||
|
||||
// Create docking hint window
|
||||
DockHintWindow.Create(win);
|
||||
WindowDragHelper.StartDragging(win, _panel.RootWindow.Window);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,6 +360,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseDown(location, button);
|
||||
MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross);
|
||||
MouseStartPosition = location;
|
||||
|
||||
// Check buttons
|
||||
if (button == MouseButton.Left)
|
||||
@@ -441,6 +447,20 @@ namespace FlaxEditor.GUI.Docking
|
||||
StartDrag(MouseDownWindow);
|
||||
MouseDownWindow = null;
|
||||
}
|
||||
// Check if single tab is tried to be moved
|
||||
else if (MouseDownWindow != null && _panel.TabsCount <= 1)
|
||||
{
|
||||
if ((MousePosition - MouseStartPosition).Length > 3)
|
||||
{
|
||||
// Clear flag
|
||||
IsMouseLeftButtonDown = false;
|
||||
|
||||
// Check tab under the mouse
|
||||
if (!IsMouseDownOverCross && MouseDownWindow != null)
|
||||
StartDrag(MouseDownWindow);
|
||||
MouseDownWindow = null;
|
||||
}
|
||||
}
|
||||
// Check if has more than one tab to change order
|
||||
else if (MouseDownWindow != null && _panel.TabsCount > 1)
|
||||
{
|
||||
|
||||
@@ -182,6 +182,25 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
|
||||
/// <param name="position">Window location.</param>
|
||||
public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent)
|
||||
{
|
||||
CreateFloating(location, size, position, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the window in a floating state.
|
||||
/// </summary>
|
||||
public void CreateFloating()
|
||||
{
|
||||
CreateFloating(Float2.Zero, Float2.Zero);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates the window in a floating state.
|
||||
/// </summary>
|
||||
/// <param name="location">Window location.</param>
|
||||
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
|
||||
/// <param name="position">Window location.</param>
|
||||
/// <param name="showWindow">Window visibility.</param>
|
||||
public void CreateFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent, bool showWindow = false)
|
||||
{
|
||||
Undock();
|
||||
|
||||
@@ -199,14 +218,17 @@ namespace FlaxEditor.GUI.Docking
|
||||
windowGUI.UnlockChildrenRecursive();
|
||||
windowGUI.PerformLayout();
|
||||
|
||||
// Show
|
||||
window.Show();
|
||||
window.BringToFront();
|
||||
window.Focus();
|
||||
OnShow();
|
||||
if (showWindow)
|
||||
{
|
||||
// Show
|
||||
window.Show();
|
||||
window.BringToFront();
|
||||
window.Focus();
|
||||
OnShow();
|
||||
|
||||
// Perform layout again
|
||||
windowGUI.PerformLayout();
|
||||
// Perform layout again
|
||||
windowGUI.PerformLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -464,7 +486,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
base.Focus();
|
||||
|
||||
SelectTab();
|
||||
SelectTab(false);
|
||||
BringToFront();
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
return;
|
||||
|
||||
// Create docking hint window
|
||||
DockHintWindow.Create(this);
|
||||
WindowDragHelper.StartDragging(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,14 +75,14 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.MaximumSize = Float2.Zero; // Unlimited size
|
||||
settings.Fullscreen = false;
|
||||
settings.HasBorder = true;
|
||||
settings.SupportsTransparency = false;
|
||||
settings.SupportsTransparency = true;
|
||||
settings.ActivateWhenFirstShown = true;
|
||||
settings.AllowInput = true;
|
||||
settings.AllowMinimize = true;
|
||||
settings.AllowMaximize = true;
|
||||
settings.AllowDragAndDrop = true;
|
||||
settings.IsTopmost = false;
|
||||
settings.IsRegularWindow = true;
|
||||
settings.Type = WindowType.Regular;
|
||||
settings.HasSizingFrame = true;
|
||||
settings.ShowAfterFirstPaint = false;
|
||||
settings.ShowInTaskbar = true;
|
||||
|
||||
@@ -81,7 +81,6 @@ namespace FlaxEditor.GUI.Docking
|
||||
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
|
||||
{
|
||||
// Check all floating windows
|
||||
// TODO: gather windows order and take it into account when performing test
|
||||
for (int i = 0; i < FloatingPanels.Count; i++)
|
||||
{
|
||||
var win = FloatingPanels[i];
|
||||
@@ -94,9 +93,44 @@ namespace FlaxEditor.GUI.Docking
|
||||
}
|
||||
|
||||
// Base
|
||||
//if (!Root?.RootWindow.Window.IsFocused ?? false)
|
||||
// return null;
|
||||
return base.HitTest(ref position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs hit test over dock panel.
|
||||
/// </summary>
|
||||
/// <param name="position">Window space position to test.</param>
|
||||
/// <param name="excluded">Floating window to omit during searching (and all docked to that one).</param>
|
||||
/// <param name="hitResults">Results of the hit test</param>
|
||||
/// <returns>True if any dock panels were hit, otherwise false.</returns>
|
||||
public bool HitTest(ref Float2 position, FloatWindowDockPanel excluded, out DockPanel[] hitResults)
|
||||
{
|
||||
// Check all floating windows
|
||||
List<DockPanel> results = new(FloatingPanels.Count);
|
||||
for (int i = 0; i < FloatingPanels.Count; i++)
|
||||
{
|
||||
var win = FloatingPanels[i];
|
||||
if (win.Visible && win != excluded)
|
||||
{
|
||||
var result = win.HitTest(ref position);
|
||||
if (result != null)
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Base
|
||||
//if (!Root?.RootWindow.Window.IsFocused ?? false)
|
||||
// return null;
|
||||
var baseResult = base.HitTest(ref position);
|
||||
if (baseResult != null)
|
||||
results.Add(baseResult);
|
||||
|
||||
hitResults = results.ToArray();
|
||||
return hitResults.Length > 0;
|
||||
}
|
||||
|
||||
internal void LinkWindow(DockWindow window)
|
||||
{
|
||||
// Add to the windows list
|
||||
|
||||
448
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
448
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
@@ -0,0 +1,448 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class used to handle docking windows dragging and docking.
|
||||
/// </summary>
|
||||
public class WindowDragHelper
|
||||
{
|
||||
private FloatWindowDockPanel _toMove;
|
||||
|
||||
private Float2 _dragOffset;
|
||||
private Rectangle _rectDock;
|
||||
private Float2 _mouse;
|
||||
private DockState _toSet;
|
||||
private DockPanel _toDock;
|
||||
private Window _dragSourceWindow;
|
||||
|
||||
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
|
||||
private Control _dockHintDown, _dockHintUp, _dockHintLeft, _dockHintRight, _dockHintCenter;
|
||||
|
||||
/// <summary>
|
||||
/// The hint control size.
|
||||
/// </summary>
|
||||
public const float HintControlSize = 32.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The opacity of the dragged window when hint controls are shown.
|
||||
/// </summary>
|
||||
public const float DragWindowOpacity = 0.4f;
|
||||
|
||||
private WindowDragHelper(FloatWindowDockPanel toMove, Window dragSourceWindow)
|
||||
{
|
||||
_toMove = toMove;
|
||||
_toSet = DockState.Float;
|
||||
var window = toMove.Window.Window;
|
||||
|
||||
// Check if window is maximized and restore window.
|
||||
if (window.IsMaximized)
|
||||
{
|
||||
// Restore window and set position to mouse.
|
||||
var mousePos = window.MousePosition;
|
||||
var previousSize = window.Size;
|
||||
window.Restore();
|
||||
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
|
||||
}
|
||||
|
||||
// Bind events
|
||||
FlaxEngine.Scripting.Update += OnUpdate;
|
||||
window.MouseUp += OnMouseUp;
|
||||
|
||||
// Update rectangles
|
||||
UpdateRects(Platform.MousePosition);
|
||||
|
||||
_dragSourceWindow = dragSourceWindow;
|
||||
if (_dragSourceWindow != null) // Detaching a tab from existing window
|
||||
{
|
||||
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
|
||||
|
||||
// TODO: when detaching tab in floating window (not main window), the drag source window is still main window?
|
||||
var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow;
|
||||
window.DoDragDrop(window.Title, _dragOffset, dragSourceWindowWayland);
|
||||
|
||||
_dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows
|
||||
}
|
||||
else
|
||||
{
|
||||
_dragOffset = window.MousePosition;
|
||||
window.DoDragDrop(window.Title, _dragOffset, window);
|
||||
}
|
||||
|
||||
// Ensure the dragged window stays on top of every other window
|
||||
window.IsAlwaysOnTop = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
var window = _toMove?.Window?.Window;
|
||||
|
||||
// Unbind events
|
||||
FlaxEngine.Scripting.Update -= OnUpdate;
|
||||
if (window != null)
|
||||
window.MouseUp -= OnMouseUp;
|
||||
if (_dragSourceWindow != null)
|
||||
_dragSourceWindow.MouseUp -= OnMouseUp;
|
||||
|
||||
RemoveDockHints();
|
||||
|
||||
if (_toMove == null)
|
||||
return;
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
window.Opacity = 1.0f;
|
||||
window.IsAlwaysOnTop = false;
|
||||
window.BringToFront();
|
||||
}
|
||||
|
||||
// Check if window won't be docked
|
||||
if (_toSet == DockState.Float)
|
||||
{
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
// Show base window
|
||||
window.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
|
||||
|
||||
// Check if window has only single tab
|
||||
if (hasNoChildPanels && _toMove.TabsCount == 1)
|
||||
{
|
||||
// Dock window
|
||||
_toMove.GetTab(0).Show(_toSet, _toDock);
|
||||
}
|
||||
// Check if dock as tab and has no child panels
|
||||
else if (hasNoChildPanels && _toSet == DockState.DockFill)
|
||||
{
|
||||
// Dock all tabs
|
||||
while (_toMove.TabsCount > 0)
|
||||
{
|
||||
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedTab = _toMove.SelectedTab;
|
||||
|
||||
// Dock the first tab into the target location
|
||||
if (_toMove.TabsCount > 0)
|
||||
{
|
||||
var firstTab = _toMove.GetTab(0);
|
||||
firstTab.Show(_toSet, _toDock);
|
||||
|
||||
// Dock rest of the tabs
|
||||
while (_toMove.TabsCount > 0)
|
||||
{
|
||||
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep selected tab being selected
|
||||
selectedTab?.SelectTab();
|
||||
}
|
||||
|
||||
// Focus target window
|
||||
_toDock.Root.Focus();
|
||||
}
|
||||
|
||||
_toMove = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start dragging a floating dock panel.
|
||||
/// </summary>
|
||||
/// <param name="toMove">Floating dock panel to move.</param>
|
||||
/// <returns>The window drag helper object.</returns>
|
||||
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove)
|
||||
{
|
||||
if (toMove == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
return new WindowDragHelper(toMove, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start dragging a docked panel into a floating window.
|
||||
/// </summary>
|
||||
/// <param name="toMove">Dock window to move.</param>
|
||||
/// <param name="dragSourceWindow">The window where dragging started from.</param>
|
||||
/// <returns>The window drag helper object.</returns>
|
||||
public static WindowDragHelper StartDragging(DockWindow toMove, Window dragSourceWindow)
|
||||
{
|
||||
if (toMove == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
// Create floating window
|
||||
toMove.CreateFloating();
|
||||
|
||||
// Get floating panel
|
||||
var window = (WindowRootControl)toMove.Root;
|
||||
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
|
||||
|
||||
return new WindowDragHelper(floatingPanelToMove, dragSourceWindow);
|
||||
}
|
||||
|
||||
private void AddDockHints()
|
||||
{
|
||||
if (_toDock == null)
|
||||
return;
|
||||
|
||||
if (_toDock.RootWindow.Window != _dragSourceWindow)
|
||||
_toDock.RootWindow.Window.MouseUp += OnMouseUp;
|
||||
|
||||
_dockHintDown = AddHintControl(new Float2(0.5f, 1));
|
||||
_dockHintUp = AddHintControl(new Float2(0.5f, 0));
|
||||
_dockHintLeft = AddHintControl(new Float2(0, 0.5f));
|
||||
_dockHintRight = AddHintControl(new Float2(1, 0.5f));
|
||||
_dockHintCenter = AddHintControl(new Float2(0.5f, 0.5f));
|
||||
|
||||
Control AddHintControl(Float2 pivot)
|
||||
{
|
||||
Control hintControl = _toDock.AddChild<Control>();
|
||||
hintControl.AnchorPreset = AnchorPresets.StretchAll;
|
||||
hintControl.Offsets = Margin.Zero;
|
||||
hintControl.Size = new Float2(HintControlSize);
|
||||
hintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
hintControl.Pivot = pivot;
|
||||
hintControl.PivotRelative = true;
|
||||
return hintControl;
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveDockHints()
|
||||
{
|
||||
if (_toDock == null)
|
||||
return;
|
||||
|
||||
if (_toDock.RootWindow.Window != _dragSourceWindow)
|
||||
_toDock.RootWindow.Window.MouseUp -= OnMouseUp;
|
||||
|
||||
_dockHintDown?.Parent.RemoveChild(_dockHintDown);
|
||||
_dockHintUp?.Parent.RemoveChild(_dockHintUp);
|
||||
_dockHintLeft?.Parent.RemoveChild(_dockHintLeft);
|
||||
_dockHintRight?.Parent.RemoveChild(_dockHintRight);
|
||||
_dockHintCenter?.Parent.RemoveChild(_dockHintCenter);
|
||||
_dockHintDown = _dockHintUp = _dockHintLeft = _dockHintRight = _dockHintCenter = null;
|
||||
}
|
||||
|
||||
private void UpdateRects(Float2 mousePos)
|
||||
{
|
||||
// Cache mouse position
|
||||
_mouse = mousePos;
|
||||
|
||||
// Check intersection with any dock panel
|
||||
DockPanel dockPanel = null;
|
||||
if (_toMove.MasterPanel.HitTest(ref _mouse, _toMove, out var hitResults))
|
||||
{
|
||||
dockPanel = hitResults[0];
|
||||
|
||||
// Prefer panel which currently has focus
|
||||
foreach (var hit in hitResults)
|
||||
{
|
||||
if (hit.RootWindow.Window.IsFocused)
|
||||
{
|
||||
dockPanel = hit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer panel in the same window we hit earlier
|
||||
if (dockPanel?.RootWindow != _toDock?.RootWindow)
|
||||
{
|
||||
foreach (var hit in hitResults)
|
||||
{
|
||||
if (hit.RootWindow == _toDock?.RootWindow)
|
||||
{
|
||||
dockPanel = _toDock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dockPanel != _toDock)
|
||||
{
|
||||
RemoveDockHints();
|
||||
_toDock = dockPanel;
|
||||
AddDockHints();
|
||||
|
||||
// Make sure the all the dock hint areas are not under other windows
|
||||
_toDock?.RootWindow.Window.BringToFront();
|
||||
//_toDock?.RootWindow.Window.Focus();
|
||||
|
||||
// Make the dragged window transparent when dock hints are visible
|
||||
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
|
||||
}
|
||||
|
||||
// Check dock state to use
|
||||
bool showProxyHints = _toDock != null;
|
||||
bool showBorderHints = showProxyHints;
|
||||
bool showCenterHint = showProxyHints;
|
||||
Control hoveredHintControl = null;
|
||||
Float2 hoveredSizeOverride = Float2.Zero;
|
||||
if (showProxyHints)
|
||||
{
|
||||
// If moved window has not only tabs but also child panels disable docking as tab
|
||||
if (_toMove.ChildPanelsCount > 0)
|
||||
showCenterHint = false;
|
||||
|
||||
// Disable docking windows with one or more dock panels inside
|
||||
if (_toMove.ChildPanelsCount > 0)
|
||||
showBorderHints = false;
|
||||
|
||||
// Get dock area
|
||||
_rectDock = _toDock.DockAreaBounds;
|
||||
|
||||
// Cache dock rectangles
|
||||
var size = _rectDock.Size / Platform.DpiScale;
|
||||
var offset = _toDock.PointFromScreen(_rectDock.Location);
|
||||
var borderMargin = 4.0f;
|
||||
var hintWindowsSize = HintControlSize;
|
||||
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
||||
var hintPreviewSize = new Float2(Math.Max(HintControlSize * 2, size.X * 0.5f), Math.Max(HintControlSize * 2, size.Y * 0.5f));
|
||||
var centerX = size.X * 0.5f;
|
||||
var centerY = size.Y * 0.5f;
|
||||
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||
|
||||
// Hit test, and calculate the approximation for filled area when hovered over the hint
|
||||
DockState toSet = DockState.Float;
|
||||
if (showBorderHints)
|
||||
{
|
||||
if (_rUpper.Contains(_toDock.PointFromScreen(_mouse)))
|
||||
{
|
||||
toSet = DockState.DockTop;
|
||||
hoveredHintControl = _dockHintUp;
|
||||
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
||||
}
|
||||
else if (_rBottom.Contains(_toDock.PointFromScreen(_mouse)))
|
||||
{
|
||||
toSet = DockState.DockBottom;
|
||||
hoveredHintControl = _dockHintDown;
|
||||
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
||||
}
|
||||
else if (_rLeft.Contains(_toDock.PointFromScreen(_mouse)))
|
||||
{
|
||||
toSet = DockState.DockLeft;
|
||||
hoveredHintControl = _dockHintLeft;
|
||||
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
|
||||
}
|
||||
else if (_rRight.Contains(_toDock.PointFromScreen(_mouse)))
|
||||
{
|
||||
toSet = DockState.DockRight;
|
||||
hoveredHintControl = _dockHintRight;
|
||||
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
|
||||
}
|
||||
}
|
||||
if (showCenterHint && _rCenter.Contains(_toDock.PointFromScreen(_mouse)))
|
||||
{
|
||||
toSet = DockState.DockFill;
|
||||
hoveredHintControl = _dockHintCenter;
|
||||
hoveredSizeOverride = new Float2(size.X, size.Y);
|
||||
}
|
||||
|
||||
_toSet = toSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
_toSet = DockState.Float;
|
||||
}
|
||||
|
||||
// Update sizes and opacity of hint controls
|
||||
if (_toDock != null)
|
||||
{
|
||||
if (hoveredHintControl != _dockHintDown)
|
||||
{
|
||||
_dockHintDown.Size = new Float2(HintControlSize);
|
||||
_dockHintDown.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintLeft)
|
||||
{
|
||||
_dockHintLeft.Size = new Float2(HintControlSize);
|
||||
_dockHintLeft.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintRight)
|
||||
{
|
||||
_dockHintRight.Size = new Float2(HintControlSize);
|
||||
_dockHintRight.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintUp)
|
||||
{
|
||||
_dockHintUp.Size = new Float2(HintControlSize);
|
||||
_dockHintUp.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintCenter)
|
||||
{
|
||||
_dockHintCenter.Size = new Float2(HintControlSize);
|
||||
_dockHintCenter.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||
}
|
||||
|
||||
if (_toSet != DockState.Float)
|
||||
{
|
||||
if (hoveredHintControl != null)
|
||||
{
|
||||
hoveredHintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(1.0f);
|
||||
hoveredHintControl.Size = hoveredSizeOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update hint controls visibility and location
|
||||
if (showProxyHints)
|
||||
{
|
||||
if (hoveredHintControl != _dockHintDown)
|
||||
_dockHintDown.Location = _rBottom.Location;
|
||||
if (hoveredHintControl != _dockHintLeft)
|
||||
_dockHintLeft.Location = _rLeft.Location;
|
||||
if (hoveredHintControl != _dockHintRight)
|
||||
_dockHintRight.Location = _rRight.Location;
|
||||
if (hoveredHintControl != _dockHintUp)
|
||||
_dockHintUp.Location = _rUpper.Location;
|
||||
if (hoveredHintControl != _dockHintCenter)
|
||||
_dockHintCenter.Location = _rCenter.Location;
|
||||
|
||||
_dockHintDown.Visible = showProxyHints & showBorderHints;
|
||||
_dockHintLeft.Visible = showProxyHints & showBorderHints;
|
||||
_dockHintRight.Visible = showProxyHints & showBorderHints;
|
||||
_dockHintUp.Visible = showProxyHints & showBorderHints;
|
||||
_dockHintCenter.Visible = showProxyHints & showCenterHint;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void OnUpdate()
|
||||
{
|
||||
var mousePos = Platform.MousePosition;
|
||||
|
||||
if (_mouse != mousePos)
|
||||
OnMouseMove(mousePos);
|
||||
}
|
||||
|
||||
private void OnMouseMove(Float2 mousePos)
|
||||
{
|
||||
if (_dragSourceWindow != null)
|
||||
_toMove.Window.Window.Position = mousePos - _dragOffset;
|
||||
|
||||
UpdateRects(mousePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,7 @@ namespace FlaxEditor.GUI.Input
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
@@ -292,13 +293,45 @@ namespace FlaxEditor.GUI.Input
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMoveRelative(Float2 mouseMotion)
|
||||
{
|
||||
var location = Root.TrackingMouseOffset;
|
||||
if (_isSliding)
|
||||
{
|
||||
// Update sliding
|
||||
ApplySliding(Root.TrackingMouseOffset.X * _slideSpeed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update cursor type so user knows they can slide value
|
||||
if (CanUseSliding && SlideRect.Contains(location) && !_isSliding)
|
||||
{
|
||||
Cursor = CursorType.SizeWE;
|
||||
_cursorChanged = true;
|
||||
}
|
||||
else if (_cursorChanged && !_isSliding)
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
_cursorChanged = false;
|
||||
}
|
||||
|
||||
base.OnMouseMoveRelative(mouseMotion);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _isSliding)
|
||||
{
|
||||
#if !PLATFORM_SDL
|
||||
// End sliding and return mouse to original location
|
||||
RootWindow.MousePosition = _mouseClickedPosition;
|
||||
#endif
|
||||
EndSliding();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace FlaxEditor.GUI
|
||||
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
||||
public sealed class MainMenu : ContainerControl
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
private bool _useCustomWindowSystem;
|
||||
private Image _icon;
|
||||
private Label _title;
|
||||
@@ -67,7 +67,7 @@ namespace FlaxEditor.GUI
|
||||
AutoFocus = false;
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
_useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
@@ -84,13 +84,15 @@ namespace FlaxEditor.GUI
|
||||
|
||||
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
|
||||
|
||||
var driver = Platform.DisplayServer;
|
||||
|
||||
_icon = new Image
|
||||
{
|
||||
Margin = new Margin(6, 6, 6, 6),
|
||||
Brush = new TextureBrush(windowIcon),
|
||||
Color = Style.Current.Foreground,
|
||||
KeepAspectRatio = false,
|
||||
TooltipText = string.Format("{0}\nVersion {1}\nConfiguration {3}\nGraphics {2}", _window.Title, Globals.EngineVersion, GPUDevice.Instance.RendererType, configuration),
|
||||
TooltipText = string.Format("{0}\nVersion {1}\nConfiguration {3}\nGraphics {2} {4}", _window.Title, Globals.EngineVersion, GPUDevice.Instance.RendererType, configuration, driver),
|
||||
Parent = this,
|
||||
};
|
||||
|
||||
@@ -166,7 +168,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
@@ -291,7 +293,7 @@ namespace FlaxEditor.GUI
|
||||
if (base.OnMouseDoubleClick(location, button))
|
||||
return true;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
var child = GetChildAtRecursive(location);
|
||||
if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
|
||||
{
|
||||
@@ -321,7 +323,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Icon
|
||||
@@ -349,7 +351,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Buttons
|
||||
@@ -367,7 +369,7 @@ namespace FlaxEditor.GUI
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace FlaxEditor.GUI
|
||||
Text = text;
|
||||
|
||||
var style = Style.Current;
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
|
||||
{
|
||||
BackgroundColorMouseOver = style.BackgroundHighlighted;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -55,18 +57,26 @@ namespace FlaxEditor.GUI
|
||||
private IsValidDelegate _isValid;
|
||||
private Action<Actor> _selected;
|
||||
|
||||
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected)
|
||||
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
|
||||
{
|
||||
_isValid = isValid;
|
||||
_selected = selected;
|
||||
|
||||
ItemClicked += OnItemClicked;
|
||||
|
||||
// TODO: use async thread to search scenes
|
||||
for (int i = 0; i < Level.ScenesCount; i++)
|
||||
if (context is PropertiesWindow propertiesWindow || context == null)
|
||||
{
|
||||
Find(Level.GetScene(i));
|
||||
// TODO: use async thread to search scenes
|
||||
for (int i = 0; i < Level.ScenesCount; i++)
|
||||
{
|
||||
Find(Level.GetScene(i));
|
||||
}
|
||||
}
|
||||
else if (context is PrefabWindow prefabWindow)
|
||||
{
|
||||
Find(prefabWindow.Graph.MainActor);
|
||||
}
|
||||
|
||||
SortItems();
|
||||
}
|
||||
|
||||
@@ -98,10 +108,11 @@ namespace FlaxEditor.GUI
|
||||
/// <param name="showTargetLocation">The show target location.</param>
|
||||
/// <param name="isValid">Event called to check if a given actor item is valid to be used.</param>
|
||||
/// <param name="selected">Event called on actor item pick.</param>
|
||||
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
|
||||
/// <returns>The dialog.</returns>
|
||||
public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected)
|
||||
public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
|
||||
{
|
||||
var popup = new ActorSearchPopup(isValid, selected);
|
||||
var popup = new ActorSearchPopup(isValid, selected, context);
|
||||
popup.Show(showTarget, showTargetLocation);
|
||||
return popup;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
@@ -66,18 +68,26 @@ namespace FlaxEditor.GUI
|
||||
private IsValidDelegate _isValid;
|
||||
private Action<Script> _selected;
|
||||
|
||||
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected)
|
||||
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
|
||||
{
|
||||
_isValid = isValid;
|
||||
_selected = selected;
|
||||
|
||||
ItemClicked += OnItemClicked;
|
||||
|
||||
// TODO: use async thread to search scenes
|
||||
for (int i = 0; i < Level.ScenesCount; i++)
|
||||
if (context is PropertiesWindow propertiesWindow || context == null)
|
||||
{
|
||||
Find(Level.GetScene(i));
|
||||
// TODO: use async thread to search scenes
|
||||
for (int i = 0; i < Level.ScenesCount; i++)
|
||||
{
|
||||
Find(Level.GetScene(i));
|
||||
}
|
||||
}
|
||||
else if (context is PrefabWindow prefabWindow)
|
||||
{
|
||||
Find(prefabWindow.Graph.MainActor);
|
||||
}
|
||||
|
||||
SortItems();
|
||||
}
|
||||
|
||||
@@ -113,10 +123,11 @@ namespace FlaxEditor.GUI
|
||||
/// <param name="showTargetLocation">The show target location.</param>
|
||||
/// <param name="isValid">Event called to check if a given script item is valid to be used.</param>
|
||||
/// <param name="selected">Event called on script item pick.</param>
|
||||
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
|
||||
/// <returns>The dialog.</returns>
|
||||
public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected)
|
||||
public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
|
||||
{
|
||||
var popup = new ScriptSearchPopup(isValid, selected);
|
||||
var popup = new ScriptSearchPopup(isValid, selected, context);
|
||||
popup.Show(showTarget, showTargetLocation);
|
||||
return popup;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using FlaxEditor.History;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using CategoryAttribute = FlaxEngine.CategoryAttribute;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
@@ -101,11 +104,26 @@ namespace FlaxEditor.GUI
|
||||
if (_isValid(type))
|
||||
{
|
||||
var attributes = type.GetAttributes(true);
|
||||
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute || x is System.Runtime.CompilerServices.CompilerGeneratedAttribute) == null)
|
||||
if (IsHideAttributes(attributes))
|
||||
{
|
||||
var mType = type.Type;
|
||||
if (mType != null && mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal))
|
||||
continue;
|
||||
if (mType != null)
|
||||
{
|
||||
// Skip if type is compiler-generated
|
||||
if (mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
// Skip if outer type is hidden
|
||||
if (mType.DeclaringType != null && IsHideAttributes(mType.DeclaringType.GetCustomAttributes(true)))
|
||||
continue;
|
||||
|
||||
// Blacklist some types
|
||||
if (typeof(TypeConverter).IsAssignableFrom(mType) ||
|
||||
typeof(IHistoryAction).IsAssignableFrom(mType) ||
|
||||
(mType.Namespace != null && mType.Namespace.StartsWith("Newtonsoft.Json")))
|
||||
continue;
|
||||
}
|
||||
|
||||
AddItem(new TypeItemView(type, attributes));
|
||||
}
|
||||
}
|
||||
@@ -113,6 +131,17 @@ namespace FlaxEditor.GUI
|
||||
SortItems();
|
||||
}
|
||||
|
||||
private bool IsHideAttributes(object[] attributes)
|
||||
{
|
||||
return attributes.FirstOrDefault(IsHideAttribute) == null;
|
||||
}
|
||||
|
||||
private bool IsHideAttribute(object attr)
|
||||
{
|
||||
return attr is HideInEditorAttribute ||
|
||||
attr is System.Runtime.CompilerServices.CompilerGeneratedAttribute;
|
||||
}
|
||||
|
||||
private void OnItemClicked(Item item)
|
||||
{
|
||||
_selected(((TypeItemView)item).Type);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
||||
class Background : ContainerControl
|
||||
{
|
||||
private readonly Timeline _timeline;
|
||||
private float[] _tickSteps;
|
||||
private double[] _tickSteps;
|
||||
private float[] _tickStrengths;
|
||||
private bool _isSelecting;
|
||||
private Float2 _selectingStartPos = Float2.Minimum;
|
||||
@@ -176,9 +176,9 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
||||
// Draw vertical lines for time axis
|
||||
var pixelsInRange = _timeline.Zoom;
|
||||
var pixelRange = pixelsInRange * (max - min);
|
||||
var tickRange = Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
||||
var tickRange = Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||
{
|
||||
var time = tick / _timeline.FramesPerSecond;
|
||||
var time = (float)tick / _timeline.FramesPerSecond;
|
||||
var x = time * zoom + Timeline.StartOffset;
|
||||
var lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
|
||||
Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor);
|
||||
@@ -233,20 +233,20 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
|
||||
var lStep = _tickSteps[l];
|
||||
var lNextStep = _tickSteps[l + 1];
|
||||
int startTick = Mathf.FloorToInt(min / lStep);
|
||||
int endTick = Mathf.CeilToInt(max / lStep);
|
||||
var startTick = Mathd.FloorToInt(min / lStep);
|
||||
var endTick = Mathd.CeilToInt(max / lStep);
|
||||
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
|
||||
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
|
||||
for (int i = startTick; i <= endTick; i++)
|
||||
for (var i = startTick; i <= endTick; i++)
|
||||
{
|
||||
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
|
||||
if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
|
||||
continue;
|
||||
var tick = i * lStep;
|
||||
var time = tick / _timeline.FramesPerSecond;
|
||||
var x = time * zoom + Timeline.StartOffset;
|
||||
var tick = (decimal)lStep * i;
|
||||
var time = (double)tick / _timeline.FramesPerSecond;
|
||||
var x = (float)time * zoom + Timeline.StartOffset;
|
||||
|
||||
// Header line
|
||||
var lineRect = new Rectangle(x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f);
|
||||
var lineRect = new Rectangle((float)x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f);
|
||||
Render2D.FillRectangle(lineRect, lineColor);
|
||||
|
||||
// Time label
|
||||
|
||||
@@ -8,7 +8,6 @@ using System.Text;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
|
||||
private void OnClickedSelect()
|
||||
{
|
||||
ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor);
|
||||
ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor, null);
|
||||
}
|
||||
|
||||
private void OnClickedSelectActor(Image image, MouseButton button)
|
||||
|
||||
@@ -19,12 +19,11 @@ namespace FlaxEditor.Gizmo
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Data
|
||||
{
|
||||
public Matrix WorldMatrix;
|
||||
public Matrix ViewProjectionMatrix;
|
||||
public Float4 GridColor;
|
||||
public Float3 ViewPos;
|
||||
public float Far;
|
||||
public Float3 Padding;
|
||||
public Float3 ViewOrigin;
|
||||
public float GridSize;
|
||||
}
|
||||
|
||||
@@ -44,6 +43,7 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
UseSingleTarget = true;
|
||||
Location = PostProcessEffectLocation.Default;
|
||||
Order = -100000; // Draw before any other editor shapes
|
||||
_shader = FlaxEngine.Content.LoadAsyncInternal<Shader>("Shaders/Editor/Grid");
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace FlaxEditor.Gizmo
|
||||
Profiler.BeginEventGPU("Editor Grid");
|
||||
|
||||
var options = Editor.Instance.Options.Options;
|
||||
Float3 camPos = renderContext.View.WorldPosition;
|
||||
float gridSize = renderContext.View.Far + 20000;
|
||||
|
||||
// Lazy-init resources
|
||||
@@ -97,10 +96,10 @@ namespace FlaxEditor.Gizmo
|
||||
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
|
||||
var vertices = new Float3[]
|
||||
{
|
||||
new Float3(-gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(-gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
new Float3(-gridSize, y, -gridSize),
|
||||
new Float3(gridSize, y, gridSize),
|
||||
new Float3(-gridSize, y, gridSize),
|
||||
new Float3(gridSize, y, -gridSize),
|
||||
};
|
||||
fixed (Float3* ptr = vertices)
|
||||
{
|
||||
@@ -113,12 +112,12 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
var data = new Data();
|
||||
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
|
||||
data.WorldMatrix = Matrix.Identity;
|
||||
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
|
||||
data.ViewPos = renderContext.View.WorldPosition;
|
||||
data.GridColor = options.Viewport.ViewportGridColor;
|
||||
data.Far = renderContext.View.Far;
|
||||
data.GridSize = options.Viewport.ViewportGridViewDistance;
|
||||
data.ViewOrigin = renderContext.View.Origin;
|
||||
context.UpdateCB(cb, new IntPtr(&data));
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
public SelectionOutline()
|
||||
{
|
||||
Order = -90000; // Draw before any other editor shapes (except grid gizmo)
|
||||
|
||||
_outlineMaterial = FlaxEngine.Content.LoadAsyncInternal<Material>("Editor/Gizmo/SelectionOutlineMaterial");
|
||||
if (_outlineMaterial)
|
||||
{
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace FlaxEditor.Gizmo
|
||||
bool isCenter = _activeAxis == Axis.Center;
|
||||
renderContext.View.GetWorldMatrix(ref _gizmoWorld, out Matrix world);
|
||||
|
||||
const sbyte sortOrder = 100; // Draw after any other editor shapes
|
||||
const float gizmoModelsScale2RealGizmoSize = 0.075f;
|
||||
Mesh cubeMesh = _modelCube.LODs[0].Meshes[0];
|
||||
Mesh sphereMesh = _modelSphere.LODs[0].Meshes[0];
|
||||
@@ -136,42 +137,42 @@ namespace FlaxEditor.Gizmo
|
||||
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
|
||||
transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3);
|
||||
transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Y axis
|
||||
Matrix.RotationX(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
|
||||
transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3);
|
||||
transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(Mathf.Pi, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
|
||||
transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3);
|
||||
transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// XY plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
|
||||
cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// ZX plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY);
|
||||
cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// YZ plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ);
|
||||
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Center sphere
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -186,22 +187,22 @@ namespace FlaxEditor.Gizmo
|
||||
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
|
||||
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3);
|
||||
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Y axis
|
||||
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
|
||||
rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1);
|
||||
rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
|
||||
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3);
|
||||
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Center box
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -216,42 +217,42 @@ namespace FlaxEditor.Gizmo
|
||||
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref mx1, out m3);
|
||||
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
|
||||
scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Y axis
|
||||
Matrix.RotationX(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
|
||||
scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(Mathf.Pi, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
|
||||
scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// XY plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
|
||||
cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// ZX plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ);
|
||||
cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// YZ plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY);
|
||||
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3);
|
||||
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
// Center box
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -263,7 +264,7 @@ namespace FlaxEditor.Gizmo
|
||||
Transform t = _vertexSnapObject?.Transform ?? _vertexSnapObjectTo.Transform;
|
||||
Vector3 p = t.LocalToWorld(_vertexSnapObject != null ? _vertexSnapPoint : _vertexSnapPointTo);
|
||||
Matrix matrix = new Transform(p, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld();
|
||||
cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix);
|
||||
cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,12 +169,12 @@ namespace FlaxEditor.Gizmo
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
|
||||
/*// Center
|
||||
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
||||
// Center
|
||||
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.Center;
|
||||
closestIntersection = intersection;
|
||||
}*/
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace FlaxEditor.Gizmo
|
||||
/// <summary>
|
||||
/// Offset to move axis away from center
|
||||
/// </summary>
|
||||
private const float AxisOffset = 0.8f;
|
||||
private const float AxisOffset = 1.2f;
|
||||
|
||||
/// <summary>
|
||||
/// How thick the axis should be
|
||||
|
||||
@@ -501,7 +501,7 @@ namespace FlaxEditor.Gizmo
|
||||
_scaleDelta = Vector3.Zero;
|
||||
|
||||
if (ActiveAxis == Axis.Center)
|
||||
scaleDelta = new Vector3(scaleDelta.AvgValue);
|
||||
scaleDelta = new Vector3(scaleDelta.ValuesSum);
|
||||
}
|
||||
|
||||
// Apply transformation (but to the parents, not whole selection pool)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Gizmo;
|
||||
@@ -149,7 +150,8 @@ namespace FlaxEditor
|
||||
private float _mouseMoveSum;
|
||||
private UndoMultiBlock _undoBlock;
|
||||
private View _view;
|
||||
private float[] _gridTickSteps = Utilities.Utils.CurveTickSteps, _gridTickStrengths;
|
||||
private double[] _gridTickSteps = Utilities.Utils.CurveTickSteps;
|
||||
private float[] _gridTickStrengths;
|
||||
private List<Widget> _widgets;
|
||||
private Widget _activeWidget;
|
||||
|
||||
@@ -563,9 +565,9 @@ namespace FlaxEditor
|
||||
var linesColor = style.ForegroundDisabled.RGBMultiplied(0.5f);
|
||||
var labelsColor = style.ForegroundDisabled;
|
||||
var labelsSize = 10.0f;
|
||||
Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
||||
Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||
{
|
||||
var p = _view.PointToParent(axis * tick);
|
||||
var p = _view.PointToParent(axis * (float)tick);
|
||||
|
||||
// Draw line
|
||||
var lineRect = new Rectangle
|
||||
@@ -640,14 +642,103 @@ namespace FlaxEditor
|
||||
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
|
||||
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
|
||||
|
||||
// TODO: draw anchors
|
||||
// Draw pivot
|
||||
var pivotSize = 8.0f;
|
||||
if (viewScale < 0.7f)
|
||||
pivotSize *= viewScale;
|
||||
var pivotX = Mathf.Remap(control.Pivot.X, 0, 1, bounds.Location.X, bounds.Location.X + bounds.Width);
|
||||
var pivotY = Mathf.Remap(control.Pivot.Y, 0, 1, bounds.Location.Y, bounds.Location.Y + bounds.Height);
|
||||
var pivotLoc = control.PointToParent(this, new Float2(pivotX, pivotY));
|
||||
var pivotRect = new Rectangle(pivotLoc - pivotSize * 0.5f, new Float2(pivotSize));
|
||||
var pivotColor = options.UIPivotColor;
|
||||
Render2D.FillRectangle(pivotRect, pivotColor);
|
||||
|
||||
// Draw anchors
|
||||
var controlParent = control.Parent;
|
||||
if (controlParent != null)
|
||||
{
|
||||
var parentBounds = controlParent.EditorBounds;
|
||||
var anchorMin = control.AnchorMin;
|
||||
var anchorMax = control.AnchorMax;
|
||||
var newMinX = Mathf.Remap(anchorMin.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
|
||||
var newMinY = Mathf.Remap(anchorMin.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
|
||||
var newMaxX = Mathf.Remap(anchorMax.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
|
||||
var newMaxY = Mathf.Remap(anchorMax.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
|
||||
|
||||
var anchorUpperLeft = controlParent.PointToParent(this, new Float2(newMinX, newMinY));
|
||||
var anchorUpperRight = controlParent.PointToParent(this, new Float2(newMaxX, newMinY));
|
||||
var anchorLowerLeft = controlParent.PointToParent(this, new Float2(newMinX, newMaxY));
|
||||
var anchorLowerRight = controlParent.PointToParent(this, new Float2(newMaxX, newMaxY));
|
||||
|
||||
var anchorRectSize = 8.0f;
|
||||
if (viewScale < 0.7f)
|
||||
anchorRectSize *= viewScale;
|
||||
|
||||
// Make anchor rects and rotate if parent is rotated.
|
||||
var parentRotation = controlParent.Rotation * Mathf.DegreesToRadians;
|
||||
|
||||
var rect1Axis = new Float2(-1, -1);
|
||||
var rect1 = new Rectangle(anchorUpperLeft +
|
||||
new Float2(anchorRectSize * rect1Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect1Axis.Y * Mathf.Sin(parentRotation),
|
||||
anchorRectSize * rect1Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect1Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||
var rect2Axis = new Float2(1, -1);
|
||||
var rect2 = new Rectangle(anchorUpperRight +
|
||||
new Float2(anchorRectSize * rect2Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect2Axis.Y * Mathf.Sin(parentRotation),
|
||||
anchorRectSize * rect2Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect2Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||
var rect3Axis = new Float2(-1, 1);
|
||||
var rect3 = new Rectangle(anchorLowerLeft +
|
||||
new Float2(anchorRectSize * rect3Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect3Axis.Y * Mathf.Sin(parentRotation),
|
||||
anchorRectSize * rect3Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect3Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||
var rect4Axis = new Float2(1, 1);
|
||||
var rect4 = new Rectangle(anchorLowerRight +
|
||||
new Float2(anchorRectSize * rect4Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect4Axis.Y * Mathf.Sin(parentRotation),
|
||||
anchorRectSize * rect4Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect4Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||
|
||||
var rectColor = options.UIAnchorColor;
|
||||
Render2D.DrawLine(anchorUpperLeft, anchorUpperRight, rectColor);
|
||||
Render2D.DrawLine(anchorUpperRight, anchorLowerRight, rectColor);
|
||||
Render2D.DrawLine(anchorLowerRight, anchorLowerLeft, rectColor);
|
||||
Render2D.DrawLine(anchorLowerLeft, anchorUpperLeft, rectColor);
|
||||
Render2D.FillRectangle(rect1, rectColor);
|
||||
Render2D.FillRectangle(rect2, rectColor);
|
||||
Render2D.FillRectangle(rect3, rectColor);
|
||||
Render2D.FillRectangle(rect4, rectColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
|
||||
{
|
||||
var style = Style.Current;
|
||||
var rect = new Rectangle((pos + resizeAxis * 10 * scale) - size * 0.5f, size);
|
||||
var control = uiControl.Control;
|
||||
var rotation = control.Rotation;
|
||||
var rotationInRadians = rotation * Mathf.DegreesToRadians;
|
||||
var rect = new Rectangle((pos +
|
||||
new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
|
||||
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 10 * scale) - size * 0.5f,
|
||||
size);
|
||||
|
||||
// Find more correct cursor at different angles
|
||||
var unwindRotation = Mathf.UnwindDegrees(rotation);
|
||||
if (unwindRotation is (>= 45 and < 135) or (> -135 and <= -45) )
|
||||
{
|
||||
switch (cursor)
|
||||
{
|
||||
case CursorType.SizeNESW:
|
||||
cursor = CursorType.SizeNWSE;
|
||||
break;
|
||||
case CursorType.SizeNS:
|
||||
cursor = CursorType.SizeWE;
|
||||
break;
|
||||
case CursorType.SizeNWSE:
|
||||
cursor = CursorType.SizeNESW;
|
||||
break;
|
||||
case CursorType.SizeWE:
|
||||
cursor = CursorType.SizeNS;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (rect.Contains(ref mousePos))
|
||||
{
|
||||
Render2D.FillRectangle(rect, style.Foreground);
|
||||
@@ -684,16 +775,15 @@ namespace FlaxEditor
|
||||
|
||||
private bool RayCastControl(ref Float2 location, out Control hit)
|
||||
{
|
||||
#if false
|
||||
// Raycast only controls with content (eg. skips transparent panels)
|
||||
return RayCastChildren(ref location, out hit);
|
||||
#else
|
||||
// Find any control under mouse (hierarchical)
|
||||
hit = GetChildAtRecursive(location);
|
||||
// First, raycast only controls with content (eg. skips transparent panels)
|
||||
RayCastChildren(ref location, out hit);
|
||||
|
||||
// If raycast failed, then find any control under mouse (hierarchical)
|
||||
hit = hit ?? GetChildAtRecursive(location);
|
||||
if (hit is View || hit is CanvasContainer)
|
||||
hit = null;
|
||||
|
||||
return hit != null;
|
||||
#endif
|
||||
}
|
||||
|
||||
private UIControlNode FindUIControlNode(Control control)
|
||||
|
||||
@@ -435,6 +435,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
||||
case InputDevice::EventType::MouseMove:
|
||||
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
|
||||
break;
|
||||
case InputDevice::EventType::MouseMoveRelative:
|
||||
window->OnMouseMoveRelative(e.MouseMovementData.PositionRelative);
|
||||
break;
|
||||
case InputDevice::EventType::MouseLeave:
|
||||
window->OnMouseLeave();
|
||||
break;
|
||||
@@ -501,7 +504,8 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
|
||||
return false;
|
||||
const ISerializable::DeserializeStream& newRootData = **newRootDataPtr;
|
||||
Guid prefabId, prefabObjectID;
|
||||
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") && JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
|
||||
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") &&
|
||||
JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
|
||||
{
|
||||
const auto nestedPrefab = Content::Load<Prefab>(prefabId);
|
||||
if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID)
|
||||
@@ -511,21 +515,6 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(void) EditorInternal_GetPrefabNestedObject(Guid* prefabId, Guid* prefabObjectId, Guid* outPrefabId, Guid* outPrefabObjectId)
|
||||
{
|
||||
*outPrefabId = Guid::Empty;
|
||||
*outPrefabObjectId = Guid::Empty;
|
||||
const auto prefab = Content::Load<Prefab>(*prefabId);
|
||||
if (!prefab)
|
||||
return;
|
||||
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(*prefabObjectId);
|
||||
if (!prefabObjectDataPtr)
|
||||
return;
|
||||
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
|
||||
JsonTools::GetGuidIfValid(*outPrefabId, prefabObjectData, "PrefabID");
|
||||
JsonTools::GetGuidIfValid(*outPrefabObjectId, prefabObjectData, "PrefabObjectID");
|
||||
}
|
||||
|
||||
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
|
||||
{
|
||||
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Content/Assets/VisualScript.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/CSG/CSGBuilder.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Renderer/ProbesRenderer.h"
|
||||
#include "Engine/Animations/Graph/AnimGraph.h"
|
||||
#include "Engine/Core/ObjectsRemovalService.h"
|
||||
#include "Engine/Level/Prefabs/Prefab.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
|
||||
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
|
||||
|
||||
@@ -592,6 +595,7 @@ bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScript
|
||||
|
||||
void ManagedEditor::WipeOutLeftoverSceneObjects()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
Array<ScriptingObject*> objects = Scripting::GetObjects();
|
||||
bool removedAny = false;
|
||||
for (ScriptingObject* object : objects)
|
||||
@@ -613,6 +617,21 @@ void ManagedEditor::WipeOutLeftoverSceneObjects()
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
|
||||
void ManagedEditor::GetPrefabNestedObject(const Guid& prefabId, const Guid& prefabObjectId, Guid& outPrefabId, Guid& outPrefabObjectId)
|
||||
{
|
||||
outPrefabId = Guid::Empty;
|
||||
outPrefabObjectId = Guid::Empty;
|
||||
const auto prefab = Content::Load<Prefab>(prefabId);
|
||||
if (!prefab)
|
||||
return;
|
||||
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(prefabObjectId);
|
||||
if (!prefabObjectDataPtr)
|
||||
return;
|
||||
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
|
||||
JsonTools::GetGuidIfValid(outPrefabId, prefabObjectData, "PrefabID");
|
||||
JsonTools::GetGuidIfValid(outPrefabObjectId, prefabObjectData, "PrefabObjectID");
|
||||
}
|
||||
|
||||
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
ASSERT(!HasManagedInstance());
|
||||
|
||||
@@ -259,6 +259,7 @@ public:
|
||||
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
|
||||
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
|
||||
API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects();
|
||||
API_FUNCTION(Internal) static void GetPrefabNestedObject(API_PARAM(Ref) const Guid& prefabId, API_PARAM(Ref) const Guid& prefabObjectId, API_PARAM(Out) Guid& outPrefabId, API_PARAM(Out) Guid& outPrefabObjectId);
|
||||
|
||||
private:
|
||||
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.Modules
|
||||
private bool _enableEvents;
|
||||
private bool _isDuringFastSetup;
|
||||
private bool _rebuildFlag;
|
||||
private bool _rebuildInitFlag;
|
||||
private int _itemsCreated;
|
||||
private int _itemsDeleted;
|
||||
private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
|
||||
@@ -61,7 +62,7 @@ namespace FlaxEditor.Modules
|
||||
public event Action WorkspaceModified;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when workspace has will be rebuilt.
|
||||
/// Occurs when workspace will be rebuilt.
|
||||
/// </summary>
|
||||
public event Action WorkspaceRebuilding;
|
||||
|
||||
@@ -88,6 +89,9 @@ namespace FlaxEditor.Modules
|
||||
|
||||
// Register AssetItems serialization helper (serialize ref ID only)
|
||||
FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter());
|
||||
|
||||
ScriptsBuilder.ScriptsReload += OnScriptsReload;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
}
|
||||
|
||||
private void OnContentAssetDisposing(Asset asset)
|
||||
@@ -817,6 +821,7 @@ namespace FlaxEditor.Modules
|
||||
Profiler.BeginEvent("ContentDatabase.Rebuild");
|
||||
var startTime = Platform.TimeSeconds;
|
||||
_rebuildFlag = false;
|
||||
_rebuildInitFlag = false;
|
||||
_enableEvents = false;
|
||||
|
||||
// Load all folders
|
||||
@@ -1008,7 +1013,7 @@ namespace FlaxEditor.Modules
|
||||
ContentItem item;
|
||||
if (path.EndsWith(".cs"))
|
||||
item = new CSharpScriptItem(path);
|
||||
else if (path.EndsWith(".cpp") || path.EndsWith(".h"))
|
||||
else if (path.EndsWith(".cpp") || path.EndsWith(".h") || path.EndsWith(".c") || path.EndsWith(".hpp"))
|
||||
item = new CppScriptItem(path);
|
||||
else if (path.EndsWith(".shader") || path.EndsWith(".hlsl"))
|
||||
item = new ShaderSourceItem(path);
|
||||
@@ -1140,6 +1145,7 @@ namespace FlaxEditor.Modules
|
||||
Proxy.Add(new CSharpEmptyStructProxy());
|
||||
Proxy.Add(new CSharpEmptyInterfaceProxy());
|
||||
Proxy.Add(new CSharpActorProxy());
|
||||
Proxy.Add(new CSharpGamePluginProxy());
|
||||
Proxy.Add(new CppAssetProxy());
|
||||
Proxy.Add(new CppStaticClassProxy());
|
||||
Proxy.Add(new CppScriptProxy());
|
||||
@@ -1229,8 +1235,6 @@ namespace FlaxEditor.Modules
|
||||
LoadProjects(Game.Project);
|
||||
}
|
||||
|
||||
RebuildInternal();
|
||||
|
||||
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
|
||||
{
|
||||
var path = obj.ResultUrl;
|
||||
@@ -1238,6 +1242,15 @@ namespace FlaxEditor.Modules
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path));
|
||||
};
|
||||
_enableEvents = true;
|
||||
_rebuildInitFlag = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndInit()
|
||||
{
|
||||
// Handle init when project was loaded without scripts loading ()
|
||||
if (_rebuildInitFlag)
|
||||
RebuildInternal();
|
||||
}
|
||||
|
||||
private void OnImportFileDone(string path)
|
||||
@@ -1312,6 +1325,52 @@ namespace FlaxEditor.Modules
|
||||
}
|
||||
}
|
||||
|
||||
private void OnScriptsReload()
|
||||
{
|
||||
var enabledEvents = _enableEvents;
|
||||
_enableEvents = false;
|
||||
_isDuringFastSetup = true;
|
||||
var startItems = _itemsCreated;
|
||||
foreach (var project in Projects)
|
||||
{
|
||||
if (project.Content != null)
|
||||
{
|
||||
//Dispose(project.Content.Folder);
|
||||
for (int i = 0; i < project.Content.Folder.Children.Count; i++)
|
||||
{
|
||||
Dispose(project.Content.Folder.Children[i]);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (project.Source != null)
|
||||
{
|
||||
//Dispose(project.Source.Folder);
|
||||
for (int i = 0; i < project.Source.Folder.Children.Count; i++)
|
||||
{
|
||||
Dispose(project.Source.Folder.Children[i]);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ContentProxy> removeProxies = new List<ContentProxy>();
|
||||
foreach (var proxy in Editor.Instance.ContentDatabase.Proxy)
|
||||
{
|
||||
if (proxy.GetType().IsCollectible)
|
||||
removeProxies.Add(proxy);
|
||||
}
|
||||
foreach (var proxy in removeProxies)
|
||||
RemoveProxy(proxy, false);
|
||||
|
||||
_isDuringFastSetup = false;
|
||||
_enableEvents = enabledEvents;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadEnd()
|
||||
{
|
||||
RebuildInternal();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnUpdate()
|
||||
{
|
||||
@@ -1339,6 +1398,8 @@ namespace FlaxEditor.Modules
|
||||
public override void OnExit()
|
||||
{
|
||||
FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing;
|
||||
ScriptsBuilder.ScriptsReload -= OnScriptsReload;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
|
||||
// Disable events
|
||||
_enableEvents = false;
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace FlaxEditor.Modules
|
||||
outputExtension = extension;
|
||||
|
||||
// Check if can place source files here
|
||||
if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h"))
|
||||
if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h" || extension == ".c" || extension == ".hpp"))
|
||||
{
|
||||
// Error
|
||||
Editor.LogWarning(string.Format("Cannot import \'{0}\' to \'{1}\'. The target directory cannot have scripts.", inputPath, targetLocation.Node.Path));
|
||||
@@ -391,6 +391,20 @@ namespace FlaxEditor.Modules
|
||||
public override void OnInit()
|
||||
{
|
||||
ImportFileEntry.RegisterDefaultTypes();
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
// Remove import file types from scripting assemblies
|
||||
List<string> removeFileTypes = new List<string>();
|
||||
foreach (var pair in ImportFileEntry.FileTypes)
|
||||
{
|
||||
if (pair.Value.Method.IsCollectible || (pair.Value.Target != null && pair.Value.Target.GetType().IsCollectible))
|
||||
removeFileTypes.Add(pair.Key);
|
||||
}
|
||||
foreach (var fileType in removeFileTypes)
|
||||
ImportFileEntry.FileTypes.Remove(fileType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -451,6 +465,7 @@ namespace FlaxEditor.Modules
|
||||
/// <inheritdoc />
|
||||
public override void OnExit()
|
||||
{
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
EndWorker();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,33 @@ namespace FlaxEditor.Modules
|
||||
Editor.Windows.ContentWin.NewItem(proxy, actor, contentItem => OnPrefabCreated(contentItem, actor, prefabWindow), actor.Name, rename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a prefab editor window.
|
||||
/// </summary>
|
||||
public void OpenPrefab(ActorNode actorNode)
|
||||
{
|
||||
if (actorNode != null)
|
||||
OpenPrefab(actorNode.Actor.PrefabID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a prefab editor window.
|
||||
/// </summary>
|
||||
public void OpenPrefab(Guid prefabID = default)
|
||||
{
|
||||
if (prefabID == Guid.Empty)
|
||||
{
|
||||
var selection = Editor.SceneEditing.Selection.Where(x => x is ActorNode actorNode && actorNode.HasPrefabLink).ToList().BuildNodesParents();
|
||||
if (selection.Count == 0 || !((ActorNode)selection[0]).Actor.HasPrefabLink)
|
||||
return;
|
||||
prefabID = ((ActorNode)selection[0]).Actor.PrefabID;
|
||||
}
|
||||
|
||||
var item = Editor.ContentDatabase.Find(prefabID);
|
||||
if (item != null)
|
||||
Editor.ContentEditing.Open(item);
|
||||
}
|
||||
|
||||
private void OnPrefabCreated(ContentItem contentItem, Actor actor, Windows.Assets.PrefabWindow prefabWindow)
|
||||
{
|
||||
if (contentItem is PrefabItem prefabItem)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user