Compare commits
213 Commits
a38cc4d5cb
...
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 | ||
| 10a906d51b | |||
| f61779119b | |||
|
|
0991628a78 | ||
|
|
703e83cd48 | ||
|
|
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
|
||||
|
||||
6
.github/workflows/cd.yml
vendored
6
.github/workflows/cd.yml
vendored
@@ -1,13 +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=10 -c lfs.transfer.maxretries=2'
|
||||
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
- name: Checkout LFS
|
||||
run: |
|
||||
git lfs version
|
||||
GIT_TRACE=1 GIT_TRANSFER_TRACE=1 git ${{ env.GIT_LFS_PULL_OPTIONS }} 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
|
||||
|
||||
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.
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -415,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"));
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -68,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
|
||||
@@ -81,17 +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.Open(Editor.Instance.ContentDatabase.FindAsset(prefab.ID));
|
||||
|
||||
// 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;
|
||||
@@ -198,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1057,6 +1057,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_scriptToggles = null;
|
||||
_scripts.Clear();
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
@@ -123,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];
|
||||
@@ -375,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()
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,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;
|
||||
|
||||
@@ -564,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
|
||||
|
||||
@@ -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);
|
||||
@@ -1230,8 +1235,6 @@ namespace FlaxEditor.Modules
|
||||
LoadProjects(Game.Project);
|
||||
}
|
||||
|
||||
RebuildInternal();
|
||||
|
||||
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
|
||||
{
|
||||
var path = obj.ResultUrl;
|
||||
@@ -1239,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)
|
||||
@@ -1313,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()
|
||||
{
|
||||
@@ -1340,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)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace FlaxEditor.Modules
|
||||
: base(editor)
|
||||
{
|
||||
// After editor cache but before the windows
|
||||
InitOrder = -900;
|
||||
InitOrder = -800;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,7 +16,7 @@ using FlaxEditor.Windows;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
using DockHintWindow = FlaxEditor.GUI.Docking.DockHintWindow;
|
||||
using WindowDragHelper = FlaxEditor.GUI.Docking.WindowDragHelper;
|
||||
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.Options;
|
||||
@@ -160,7 +160,7 @@ namespace FlaxEditor.Modules
|
||||
internal UIModule(Editor editor)
|
||||
: base(editor)
|
||||
{
|
||||
InitOrder = -90;
|
||||
InitOrder = -70;
|
||||
VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface");
|
||||
ColorValueBox.ShowPickColorDialog += ShowPickColorDialog;
|
||||
}
|
||||
@@ -381,7 +381,7 @@ namespace FlaxEditor.Modules
|
||||
Editor.Options.OptionsChanged += OnOptionsChanged;
|
||||
|
||||
// Add dummy control for drawing the main window borders if using a custom style
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (!Editor.Options.Options.Interface.UseNativeWindowSystem)
|
||||
#endif
|
||||
{
|
||||
@@ -456,13 +456,6 @@ namespace FlaxEditor.Modules
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnExit()
|
||||
{
|
||||
// Cleanup dock panel hint proxy windows (Flax will destroy them by var but it's better to clear them earlier)
|
||||
DockHintWindow.Proxy.Dispose();
|
||||
}
|
||||
|
||||
private IColorPickerDialog ShowPickColorDialog(Control targetControl, Color initialValue, ColorValueBox.ColorPickerEvent colorChanged, ColorValueBox.ColorPickerClosedEvent pickerClosed, bool useDynamicEditing)
|
||||
{
|
||||
var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing);
|
||||
|
||||
@@ -5,10 +5,12 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.Dialogs;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
using FlaxEditor.Windows.Profiler;
|
||||
@@ -39,6 +41,7 @@ namespace FlaxEditor.Modules
|
||||
|
||||
public DockState DockState;
|
||||
public DockPanel DockedTo;
|
||||
public int DockedTabIndex;
|
||||
public float? SplitterValue = null;
|
||||
|
||||
public bool SelectOnShow = false;
|
||||
@@ -48,6 +51,8 @@ namespace FlaxEditor.Modules
|
||||
public Float2 FloatSize;
|
||||
public Float2 FloatPosition;
|
||||
|
||||
public Guid AssetItemID;
|
||||
|
||||
// Constructor, to allow for default values
|
||||
public WindowRestoreData()
|
||||
{
|
||||
@@ -760,8 +765,10 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
settings.HasBorder = false;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Skip OS sizing frame and implement it using LeftButtonHit
|
||||
settings.HasSizingFrame = false;
|
||||
#endif
|
||||
}
|
||||
#elif PLATFORM_LINUX
|
||||
settings.HasBorder = false;
|
||||
@@ -803,43 +810,64 @@ namespace FlaxEditor.Modules
|
||||
Level.SceneSaving += OnSceneSaving;
|
||||
Level.SceneUnloaded += OnSceneUnloaded;
|
||||
Level.SceneUnloading += OnSceneUnloading;
|
||||
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
|
||||
Editor.ContentDatabase.WorkspaceRebuilt += OnWorkspaceRebuilt;
|
||||
Editor.StateMachine.StateChanged += OnEditorStateChanged;
|
||||
}
|
||||
|
||||
internal void AddToRestore(AssetEditorWindow win)
|
||||
{
|
||||
AddToRestore(win, win.GetType(), new WindowRestoreData
|
||||
{
|
||||
AssetItemID = win.Item.ID,
|
||||
});
|
||||
}
|
||||
|
||||
internal void AddToRestore(CustomEditorWindow win)
|
||||
{
|
||||
var type = win.GetType();
|
||||
AddToRestore(win.Window, win.GetType(), new WindowRestoreData());
|
||||
}
|
||||
|
||||
private void AddToRestore(EditorWindow win, Type type, WindowRestoreData winData)
|
||||
{
|
||||
// Validate if can restore type
|
||||
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
|
||||
if (constructor == null || type.IsGenericType)
|
||||
return;
|
||||
|
||||
var winData = new WindowRestoreData();
|
||||
var panel = win.Window.ParentDockPanel;
|
||||
var panel = win.ParentDockPanel;
|
||||
|
||||
// Ensure that this window is only selected following recompilation
|
||||
// if it was the active tab in its dock panel. Otherwise, there is a
|
||||
// risk of interrupting the user's workflow by potentially selecting
|
||||
// background tabs.
|
||||
winData.SelectOnShow = panel.SelectedTab == win.Window;
|
||||
if (panel is FloatWindowDockPanel)
|
||||
var window = win.RootWindow.Window;
|
||||
winData.SelectOnShow = panel.SelectedTab == win;
|
||||
winData.DockedTabIndex = 0;
|
||||
if (panel is FloatWindowDockPanel && window != null && panel.TabsCount == 1)
|
||||
{
|
||||
winData.DockState = DockState.Float;
|
||||
var window = win.Window.RootWindow.Window;
|
||||
winData.FloatPosition = window.Position;
|
||||
winData.FloatSize = window.ClientSize;
|
||||
winData.Maximize = window.IsMaximized;
|
||||
winData.Minimize = window.IsMinimized;
|
||||
winData.DockedTo = panel;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < panel.Tabs.Count; i++)
|
||||
{
|
||||
if (panel.Tabs[i] == win)
|
||||
{
|
||||
winData.DockedTabIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (panel.TabsCount > 1)
|
||||
{
|
||||
winData.DockState = DockState.DockFill;
|
||||
winData.DockedTo = panel;
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||
winData.DockedTo = panel.ParentDockPanel;
|
||||
@@ -851,38 +879,93 @@ namespace FlaxEditor.Modules
|
||||
_restoreWindows.Add(winData);
|
||||
}
|
||||
|
||||
private void OnScriptsReloadEnd()
|
||||
private void OnWorkspaceRebuilt()
|
||||
{
|
||||
for (int i = 0; i < _restoreWindows.Count; i++)
|
||||
// Go in reverse order to create floating Prefab windows first before docked windows
|
||||
for (int i = _restoreWindows.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var winData = _restoreWindows[i];
|
||||
|
||||
try
|
||||
{
|
||||
var assembly = Utils.GetAssemblyByName(winData.AssemblyName);
|
||||
if (assembly != null)
|
||||
if (assembly == null)
|
||||
continue;
|
||||
|
||||
var type = assembly.GetType(winData.TypeName);
|
||||
if (type == null)
|
||||
continue;
|
||||
|
||||
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
|
||||
{
|
||||
var type = assembly.GetType(winData.TypeName);
|
||||
if (type != null)
|
||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
|
||||
var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
|
||||
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
|
||||
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
{
|
||||
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
||||
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
var window = win.RootWindow.Window;
|
||||
window.Position = winData.FloatPosition;
|
||||
if (winData.Maximize)
|
||||
{
|
||||
var window = win.Window.RootWindow.Window;
|
||||
window.Position = winData.FloatPosition;
|
||||
if (winData.Maximize)
|
||||
{
|
||||
window.Maximize();
|
||||
}
|
||||
else if (winData.Minimize)
|
||||
{
|
||||
window.Minimize();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.ClientSize = winData.FloatSize;
|
||||
}
|
||||
window.Maximize();
|
||||
}
|
||||
else if (winData.Minimize)
|
||||
{
|
||||
window.Minimize();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.ClientSize = winData.FloatSize;
|
||||
}
|
||||
|
||||
// Update panel reference in other windows docked to this panel
|
||||
foreach (ref var otherData in CollectionsMarshal.AsSpan(_restoreWindows))
|
||||
{
|
||||
if (otherData.DockedTo == winData.DockedTo)
|
||||
otherData.DockedTo = win.ParentDockPanel;
|
||||
}
|
||||
}
|
||||
var panel = win.ParentDockPanel;
|
||||
int currentTabIndex = 0;
|
||||
for (int pi = 0; pi < panel.TabsCount; pi++)
|
||||
{
|
||||
if (panel.Tabs[pi] == win)
|
||||
{
|
||||
currentTabIndex = pi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (currentTabIndex > winData.DockedTabIndex)
|
||||
{
|
||||
win.ParentDockPanel.MoveTabLeft(currentTabIndex);
|
||||
currentTabIndex--;
|
||||
}
|
||||
while (currentTabIndex < winData.DockedTabIndex)
|
||||
{
|
||||
win.ParentDockPanel.MoveTabRight(currentTabIndex);
|
||||
currentTabIndex++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
||||
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
{
|
||||
var window = win.Window.RootWindow.Window;
|
||||
window.Position = winData.FloatPosition;
|
||||
if (winData.Maximize)
|
||||
{
|
||||
window.Maximize();
|
||||
}
|
||||
else if (winData.Minimize)
|
||||
{
|
||||
window.Minimize();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.ClientSize = winData.FloatSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,6 +976,11 @@ namespace FlaxEditor.Modules
|
||||
Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName));
|
||||
}
|
||||
}
|
||||
|
||||
// Restored windows stole the focus from Editor
|
||||
if (_restoreWindows.Count > 0)
|
||||
Editor.Instance.Windows.MainWindow.Focus();
|
||||
|
||||
_restoreWindows.Clear();
|
||||
}
|
||||
|
||||
@@ -1048,7 +1136,7 @@ namespace FlaxEditor.Modules
|
||||
Level.SceneSaving -= OnSceneSaving;
|
||||
Level.SceneUnloaded -= OnSceneUnloaded;
|
||||
Level.SceneUnloading -= OnSceneUnloading;
|
||||
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
|
||||
Editor.ContentDatabase.WorkspaceRebuilt -= OnWorkspaceRebuilt;
|
||||
Editor.StateMachine.StateChanged -= OnEditorStateChanged;
|
||||
|
||||
// Close main window
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using static FlaxEditor.Viewport.EditorViewport;
|
||||
|
||||
namespace FlaxEditor.Options
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace FlaxEditor.Options
|
||||
[HideInEditor]
|
||||
[TypeConverter(typeof(InputBindingConverter))]
|
||||
[CustomEditor(typeof(InputBindingEditor))]
|
||||
public struct InputBinding
|
||||
public struct InputBinding : IEquatable<InputBinding>
|
||||
{
|
||||
/// <summary>
|
||||
/// The key to bind.
|
||||
@@ -251,6 +252,40 @@ namespace FlaxEditor.Options
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(InputBinding other)
|
||||
{
|
||||
return Key == other.Key && Modifier1 == other.Modifier1 && Modifier2 == other.Modifier2;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is InputBinding other && Equals(other);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine((int)Key, (int)Modifier1, (int)Modifier2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two values.
|
||||
/// </summary>
|
||||
public static bool operator ==(InputBinding left, InputBinding right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two values.
|
||||
/// </summary>
|
||||
public static bool operator !=(InputBinding left, InputBinding right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
class InputBindingConverter : TypeConverter
|
||||
@@ -522,5 +557,27 @@ namespace FlaxEditor.Options
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes a specific binding.
|
||||
/// </summary>
|
||||
/// <param name="editor">The editor instance.</param>
|
||||
/// <param name="binding">The binding to execute.</param>
|
||||
/// <returns>True if event has been handled, otherwise false.</returns>
|
||||
public bool Invoke(Editor editor, InputBinding binding)
|
||||
{
|
||||
if (binding == new InputBinding())
|
||||
return false;
|
||||
var options = editor.Options.Options.Input;
|
||||
for (int i = 0; i < Bindings.Count; i++)
|
||||
{
|
||||
if (Bindings[i].Binder(options) == binding)
|
||||
{
|
||||
Bindings[i].Callback();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,32 @@ using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Options
|
||||
{
|
||||
/// <summary>
|
||||
/// Action to perform when a Scene Node receive a double mouse left click.
|
||||
/// </summary>
|
||||
public enum SceneNodeDoubleClick
|
||||
{
|
||||
/// <summary>
|
||||
/// Toggles expand/state of the node.
|
||||
/// </summary>
|
||||
Expand,
|
||||
|
||||
/// <summary>
|
||||
/// Rename the node.
|
||||
/// </summary>
|
||||
RenameActor,
|
||||
|
||||
/// <summary>
|
||||
/// Focus the object in the viewport.
|
||||
/// </summary>
|
||||
FocusActor,
|
||||
|
||||
/// <summary>
|
||||
/// If possible, open the scene node in an associated Editor (eg. Prefab Editor).
|
||||
/// </summary>
|
||||
OpenPrefab,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input editor options data container.
|
||||
/// </summary>
|
||||
@@ -344,6 +370,10 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface"), EditorOrder(2020)]
|
||||
public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(SceneNodeDoubleClick.Expand)]
|
||||
[EditorDisplay("Interface"), EditorOrder(2030)]
|
||||
public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// Focus the Game Window. On play mode end restore focus to the previous window.
|
||||
/// </summary>
|
||||
GameWindowThenRestore,
|
||||
GameWindowThenRestore,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,7 +167,7 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface"), EditorOrder(10), Tooltip("Editor User Interface scale. Applied to all UI elements, windows and text. Can be used to scale the interface up on a bigger display. Editor restart required.")]
|
||||
public float InterfaceScale { get; set; } = 1.0f;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether use native window title bar. Editor restart required.
|
||||
/// </summary>
|
||||
@@ -379,6 +379,22 @@ namespace FlaxEditor.Options
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output log text color for warnings
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "1,1,0,1")]
|
||||
[EditorDisplay("Output Log", "Warning Color"), EditorOrder(446), Tooltip("The output log text color for warnings.")]
|
||||
public Color OutputLogWarningTextColor { get; set; } = Color.Yellow;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output log text color for errors
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "1,0,0,1")]
|
||||
[EditorDisplay("Output Log", "Error Color"), EditorOrder(445), Tooltip("The output log text color for errors.")]
|
||||
public Color OutputLogErrorTextColor { get; set; } = Color.Red;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether auto-focus output log window on code compilation error.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.Drag;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Utilities;
|
||||
using FlaxEditor.Windows;
|
||||
@@ -15,7 +16,6 @@ using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.GUI
|
||||
{
|
||||
@@ -393,7 +393,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
/// <summary>
|
||||
/// Starts the actor renaming action.
|
||||
/// </summary>
|
||||
public void StartRenaming(EditorWindow window, Panel treePanel = null)
|
||||
public void StartRenaming(EditorWindow window = null, Panel treePanel = null)
|
||||
{
|
||||
// Block renaming during scripts reload
|
||||
if (Editor.Instance.ProgressReporting.CompileScripts.IsActive)
|
||||
@@ -461,6 +461,30 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool OnMouseDoubleClickHeader(ref Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
var sceneContext = this.GetSceneContext();
|
||||
switch (Editor.Instance.Options.Options.Input.DoubleClickSceneNode)
|
||||
{
|
||||
case SceneNodeDoubleClick.RenameActor:
|
||||
sceneContext.RenameSelection();
|
||||
return true;
|
||||
case SceneNodeDoubleClick.FocusActor:
|
||||
sceneContext.FocusSelection();
|
||||
return true;
|
||||
case SceneNodeDoubleClick.OpenPrefab:
|
||||
Editor.Instance.Prefabs.OpenPrefab(ActorNode);
|
||||
return true;
|
||||
case SceneNodeDoubleClick.Expand:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return base.OnMouseDoubleClickHeader(ref location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override DragDropEffect OnDragEnterHeader(DragData data)
|
||||
{
|
||||
|
||||
@@ -469,6 +469,7 @@ namespace FlaxEditor.SceneGraph
|
||||
{
|
||||
ChildNodes[i].OnDispose();
|
||||
}
|
||||
ChildNodes.Clear();
|
||||
|
||||
SceneGraphFactory.Nodes.Remove(ID);
|
||||
}
|
||||
|
||||
@@ -120,9 +120,13 @@ void ScriptsBuilderImpl::sourceDirEvent(const String& path, FileSystemAction act
|
||||
// Discard non-source files or generated files
|
||||
if ((!path.EndsWith(TEXT(".cs")) &&
|
||||
!path.EndsWith(TEXT(".cpp")) &&
|
||||
!path.EndsWith(TEXT(".c")) &&
|
||||
!path.EndsWith(TEXT(".hpp")) &&
|
||||
!path.EndsWith(TEXT(".h"))) ||
|
||||
path.EndsWith(TEXT(".Gen.cs")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeLock scopeLock(_locker);
|
||||
_lastSourceCodeEdited = DateTime::Now();
|
||||
|
||||
@@ -161,6 +161,8 @@ namespace FlaxEditor.Surface
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_nodesCache.Clear();
|
||||
|
||||
// Check if any of the nodes comes from the game scripts - those can be reloaded at runtime so prevent crashes
|
||||
bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts;
|
||||
|
||||
|
||||
@@ -1182,9 +1182,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void DrawEditorBackground(ref Rectangle rect)
|
||||
public override void DrawEditorGrid(ref Rectangle rect)
|
||||
{
|
||||
base.DrawEditorBackground(ref rect);
|
||||
base.DrawEditorGrid(ref rect);
|
||||
|
||||
// Draw triangulated multi blend space
|
||||
var style = Style.Current;
|
||||
@@ -1195,15 +1195,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
else
|
||||
Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f));
|
||||
Render2D.DrawTriangles(_triangles, style.Foreground);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void DrawEditorGrid(ref Rectangle rect)
|
||||
{
|
||||
base.DrawEditorGrid(ref rect);
|
||||
|
||||
// Highlight selected blend point
|
||||
var style = Style.Current;
|
||||
var selectedIndex = _selectedAnimation.SelectedIndex;
|
||||
if (selectedIndex != -1 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver))
|
||||
{
|
||||
|
||||
@@ -87,11 +87,17 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
private class GradientStop : Control
|
||||
{
|
||||
private bool _isMoving;
|
||||
private float _movedToTime = float.MaxValue;
|
||||
private Float2 _startMovePos;
|
||||
|
||||
public ColorGradientNode Node;
|
||||
public Color Color;
|
||||
|
||||
public void UpdateLocation(float time)
|
||||
{
|
||||
Location = Node._gradient.BottomLeft + new Float2(time * Node._gradient.Width - Width * 0.5f, 0.0f);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
@@ -118,6 +124,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
Node.Select(this);
|
||||
_movedToTime = float.MaxValue;
|
||||
_isMoving = true;
|
||||
_startMovePos = location;
|
||||
StartMouseCapture();
|
||||
@@ -133,6 +140,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (button == MouseButton.Left && _isMoving)
|
||||
{
|
||||
_isMoving = false;
|
||||
if (_movedToTime < float.MaxValue)
|
||||
{
|
||||
int index = Node._stops.IndexOf(this);
|
||||
Node.SetStopTime(index, _movedToTime);
|
||||
_movedToTime = float.MaxValue;
|
||||
}
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
@@ -159,9 +172,10 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (_isMoving && Float2.DistanceSquared(ref location, ref _startMovePos) > 25.0f)
|
||||
{
|
||||
_startMovePos = Float2.Minimum;
|
||||
var index = Node._stops.IndexOf(this);
|
||||
var time = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width;
|
||||
Node.SetStopTime(index, time);
|
||||
int index = Node._stops.IndexOf(this);
|
||||
_movedToTime = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width;
|
||||
_movedToTime = Node.ClampStopTime(index, _movedToTime);
|
||||
UpdateLocation(_movedToTime);
|
||||
}
|
||||
|
||||
base.OnMouseMove(location);
|
||||
@@ -171,6 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
_isMoving = false;
|
||||
_movedToTime = float.MaxValue;
|
||||
|
||||
base.OnEndMouseCapture();
|
||||
}
|
||||
@@ -223,6 +238,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Parent = this
|
||||
};
|
||||
_timeValue.ValueChanged += OnTimeValueChanged;
|
||||
_timeValue.SlidingEnd += OnTimeValueChanged;
|
||||
|
||||
_colorValue = new ColorValueBox(Color.Black, _timeValue.Right + 4.0f, controlsLevel)
|
||||
{
|
||||
@@ -301,8 +317,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
private void OnTimeValueChanged()
|
||||
{
|
||||
var time = _timeValue.Value;
|
||||
var index = _stops.IndexOf(_selected);
|
||||
SetStopTime(index, _timeValue.Value);
|
||||
if (_timeValue.IsSliding)
|
||||
{
|
||||
// Preview-only while sliding
|
||||
time = ClampStopTime(index, time);
|
||||
_selected.UpdateLocation(time);
|
||||
return;
|
||||
}
|
||||
SetStopTime(index, time);
|
||||
}
|
||||
|
||||
private void OnColorValueChanged()
|
||||
@@ -346,7 +370,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
UpdateStops();
|
||||
}
|
||||
|
||||
private void SetStopTime(int index, float time)
|
||||
private float ClampStopTime(int index, float time)
|
||||
{
|
||||
time = Mathf.Saturate(time);
|
||||
if (index != 0)
|
||||
@@ -357,6 +381,12 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
time = Mathf.Min(time, (float)Values[1 + index * 2 + 2]);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
private void SetStopTime(int index, float time)
|
||||
{
|
||||
time = ClampStopTime(index, time);
|
||||
SetValue(1 + index * 2, time);
|
||||
}
|
||||
|
||||
@@ -395,7 +425,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
var stop = _stops[i];
|
||||
var time = (float)Values[i * 2 + 1];
|
||||
stop.Location = _gradient.BottomLeft + new Float2(time * _gradient.Width - stop.Width * 0.5f, 0.0f);
|
||||
stop.UpdateLocation(time);
|
||||
stop.Color = (Color)Values[i * 2 + 2];
|
||||
stop.TooltipText = stop.Color + " at " + time;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FlaxEditor.Surface
|
||||
public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
|
||||
: base(owner, onSave, undo, CreateStyle())
|
||||
{
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private static SurfaceStyle CreateStyle()
|
||||
@@ -35,6 +36,11 @@ namespace FlaxEditor.Surface
|
||||
return style;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_nodesCache.Clear();
|
||||
}
|
||||
|
||||
private static void DrawBox(Box box)
|
||||
{
|
||||
var rect = new Rectangle(Float2.Zero, box.Size);
|
||||
@@ -186,6 +192,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
_nodesCache.Wait();
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
@@ -415,6 +415,15 @@ namespace FlaxEditor.Surface
|
||||
// Init drag handlers
|
||||
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
|
||||
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_activeVisjectCM = null;
|
||||
_cmPrimaryMenu?.Dispose();
|
||||
_cmPrimaryMenu = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1023,6 +1032,8 @@ namespace FlaxEditor.Surface
|
||||
_activeVisjectCM = null;
|
||||
_cmPrimaryMenu?.Dispose();
|
||||
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,12 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
_supportsImplicitCastFromObjectToBoolean = true;
|
||||
DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor));
|
||||
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||
}
|
||||
|
||||
private void OnScriptsReloadBegin()
|
||||
{
|
||||
_nodesCache.Clear();
|
||||
}
|
||||
|
||||
private bool ValidateDragActor(ActorNode actor)
|
||||
@@ -631,6 +637,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
if (IsDisposing)
|
||||
return;
|
||||
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||
_nodesCache.Wait();
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user