Compare commits
343 Commits
mac_change
...
83512822b1
| Author | SHA1 | Date | |
|---|---|---|---|
| 83512822b1 | |||
| ccb78103ec | |||
| 6e79ffea34 | |||
| 4f03d37a17 | |||
|
|
6479a3d3c6 | ||
|
|
e41c48f9e5 | ||
|
|
9cfcbfa9d2 | ||
|
|
bcd2b1f0f2 | ||
| 6fb8419b3c | |||
| a4272d6ca9 | |||
|
|
eb6010cba7 | ||
|
|
5a23060e05 | ||
|
|
b92c18cf25 | ||
|
|
6a82eb114d | ||
|
|
97b37b3ce4 | ||
| 4654117d5e | |||
|
|
22911bbc45 | ||
|
|
cae2720585 | ||
|
|
90b6293bc2 | ||
|
|
117f890612 | ||
|
|
a6a2fd2c66 | ||
|
|
a05ca12770 | ||
|
|
abe7785e94 | ||
|
|
2cedac8d96 | ||
|
|
ea854a0f7b | ||
|
|
d0817809ff | ||
|
|
95f2216f97 | ||
|
|
7e5edf1b33 | ||
|
|
c649a4f4b2 | ||
| 6ff260d052 | |||
| 88d2b72822 | |||
|
|
3c74b315a8 | ||
|
|
f841575378 | ||
|
|
d90377ed62 | ||
|
|
c8d622bda9 | ||
|
|
fbf2d8f567 | ||
|
|
42687a792c | ||
|
|
5c43d35146 | ||
|
|
c1e1dee975 | ||
|
|
742d74a2d0 | ||
|
|
614ffa70a0 | ||
|
|
4b4331fd70 | ||
|
|
e221f7204b | ||
|
|
18fa8e1c47 | ||
|
|
2f02ec52ed | ||
|
|
9464f97e16 | ||
|
|
54467a4a5e | ||
|
|
3a9e175043 | ||
|
|
9dff048cb5 | ||
|
|
f376fd50a9 | ||
|
|
e27cf04f91 | ||
|
|
648504ceb1 | ||
|
|
e2f741cab9 | ||
|
|
214ec9f2b1 | ||
|
|
27ac755bbe | ||
|
|
00055ef663 | ||
|
|
aa59a6faf7 | ||
|
|
e7d2025010 | ||
|
|
b418ab5275 | ||
|
|
c1e782bb32 | ||
|
|
e1a2a36978 | ||
|
|
793bc33b2f | ||
|
|
2109a2d261 | ||
|
|
9e50a39ebf | ||
|
|
7fc564a0ac | ||
|
|
8dfb564fb3 | ||
|
|
f8daff273a | ||
|
|
112e728465 | ||
| 29868531ad | |||
| 95dfb6fdc6 | |||
|
|
9c9d560ce5 | ||
|
|
f1945552ab | ||
|
|
ecd5559aad | ||
|
|
1fa83639c2 | ||
|
|
568719b615 | ||
|
|
74000fa766 | ||
|
|
1d63067614 | ||
|
|
85fd1389db | ||
|
|
cce042045e | ||
|
|
53e3cee196 | ||
|
|
6ee3b23261 | ||
|
|
1a77ba4552 | ||
|
|
eee4e55cf0 | ||
|
|
c2cbaeed30 | ||
|
|
e982a23ed3 | ||
|
|
f6feae5cf2 | ||
|
|
ba75fd5882 | ||
|
|
1eaf40f2f7 | ||
|
|
fe98a23cb4 | ||
|
|
77bf03128e | ||
|
|
8f49a492d8 | ||
| 8df3999f85 | |||
|
|
496856d12e | ||
|
|
e97d683545 | ||
|
|
ae44d47043 | ||
|
|
8b88def9d0 | ||
|
|
fa97229830 | ||
|
|
1946caac6e | ||
|
|
6f5308126b | ||
|
|
6a0c734cec | ||
|
|
13b8863f0c | ||
|
|
f2aaad0048 | ||
|
|
55b441e9fa | ||
|
|
6fece4ca38 | ||
|
|
2fd9b4a62a | ||
|
|
077f7a3cd1 | ||
|
|
7da69f18d4 | ||
| 6c63c2f650 | |||
| 149b189629 | |||
|
|
fd8a8b5a4d | ||
| b1fd86e6b5 | |||
| 5e8fdf879d | |||
|
|
fa89e710d8 | ||
|
|
b51ba58063 | ||
|
|
057489e5b9 | ||
|
|
5bae695ae9 | ||
|
|
5b3ed1fbc3 | ||
|
|
f5092e5262 | ||
|
|
3bd6160c3b | ||
|
|
1d0a0a409d | ||
|
|
eb90ab84f2 | ||
|
|
6f37525674 | ||
|
|
eeb8a7ea41 | ||
|
|
df0b571c50 | ||
|
|
ec22427acd | ||
|
|
6c499e877f | ||
|
|
4d9407e4e9 | ||
|
|
28c70f5078 | ||
|
|
14806a1ac7 | ||
|
|
1ebb3e67d6 | ||
|
|
991cdbb9a0 | ||
|
|
278b177c46 | ||
|
|
0630b6257a | ||
|
|
f86d9c47b7 | ||
|
|
ae2088bb9d | ||
|
|
9340c42f2b | ||
|
|
8d7dfd5946 | ||
|
|
894cb273aa | ||
|
|
2996e0c53c | ||
|
|
79ce82d8a0 | ||
|
|
3c8e59c114 | ||
|
|
1493571810 | ||
|
|
a613d89f47 | ||
|
|
5471c59d5f | ||
|
|
ac42223f9e | ||
|
|
c21c9c13ad | ||
|
|
8251509607 | ||
|
|
3083e3f611 | ||
|
|
66add1f3bd | ||
|
|
b8a680df57 | ||
|
|
e969b7fffb | ||
|
|
5d9657781a | ||
|
|
2cd03787cd | ||
|
|
619c5ac3b0 | ||
|
|
89baa91552 | ||
|
|
83b3b1af76 | ||
|
|
19148f21ac | ||
|
|
2da8e392db | ||
|
|
a812b8b108 | ||
|
|
3dc96352e6 | ||
|
|
c2b590d2cf | ||
|
|
842d6969fe | ||
|
|
0f3044ae72 | ||
|
|
11dec8e868 | ||
|
|
d6b1f06721 | ||
|
|
14fcc593c7 | ||
|
|
08ed5ae483 | ||
|
|
b065e6c989 | ||
|
|
372a23cf3a | ||
|
|
4721e8109f | ||
|
|
b58aaccc53 | ||
|
|
294dd3d363 | ||
|
|
e00f552baf | ||
|
|
ae9ded504d | ||
|
|
9753e579c1 | ||
|
|
2e996c8e91 | ||
|
|
545a43de32 | ||
|
|
e606c35093 | ||
|
|
21ae2d5d40 | ||
|
|
4649298605 | ||
|
|
ae9622d271 | ||
|
|
4366976015 | ||
|
|
5b2a966ac6 | ||
|
|
59308df250 | ||
|
|
9ba1c4c338 | ||
|
|
ec2957bf38 | ||
|
|
8bb5655b2f | ||
|
|
c24ecaaab1 | ||
|
|
483a33996f | ||
|
|
6be8158209 | ||
|
|
8e7fcd3cad | ||
|
|
a792a8a533 | ||
|
|
25d8c4645e | ||
|
|
64c552d69d | ||
|
|
fafa400db0 | ||
|
|
0b20a5342e | ||
|
|
fa4e56a32a | ||
|
|
212bd7a011 | ||
|
|
943864004f | ||
|
|
8ce4d94a96 | ||
|
|
6be193bfbf | ||
|
|
5d3947f117 | ||
|
|
c7bb7be20f | ||
|
|
f74b96bcb6 | ||
|
|
cecfea1ecf | ||
|
|
09ce2b5a6d | ||
|
|
2f9cdadb11 | ||
|
|
e218ce2d85 | ||
|
|
5ec6993342 | ||
|
|
87787cb5bf | ||
|
|
5b618b4f31 | ||
|
|
08a86066d0 | ||
|
|
388eb654a5 | ||
|
|
d8059c3db3 | ||
| 559d17e6c3 | |||
|
|
dfe177447c | ||
|
|
2a5aed6c15 | ||
|
|
f5ad8566eb | ||
| 7c5628d47e | |||
| 9645008460 | |||
| 12dbf09164 | |||
| f09fd7ad34 | |||
| 8986290b12 | |||
| 9a4d3a56a3 | |||
|
|
b0048d6540 | ||
|
|
b1b36ea1a3 | ||
|
|
e568e6e17b | ||
|
|
af955ba418 | ||
|
|
a56e2e7b1e | ||
|
|
a0cdb08893 | ||
|
|
fbb829a915 | ||
|
|
5790da6167 | ||
|
|
c6e4fbd966 | ||
|
|
101ea44051 | ||
|
|
d6c6936f6d | ||
|
|
4929e8172c | ||
|
|
8c83156133 | ||
|
|
d587921a83 | ||
|
|
6fe6ba20fb | ||
|
|
2ea3cde203 | ||
|
|
059fe98c67 | ||
|
|
1ab05b620a | ||
|
|
4b387d040d | ||
|
|
9d527ab4a6 | ||
|
|
bbc221086a | ||
|
|
e5b7e58a07 | ||
|
|
cfef93134e | ||
| 84ada18299 | |||
| 635fe8017e | |||
| 834380ff05 | |||
| dd65fc2289 | |||
| 86125bb625 | |||
| 09a9d8b380 | |||
| 86b223ec93 | |||
| 78f6080321 | |||
| c7be6f6e0e | |||
| c40c31fbb7 | |||
| f5fbc1e32d | |||
| 0a20378acd | |||
| d4e87877b6 | |||
| 7eb7236b8a | |||
| dc0e4ffce2 | |||
| 86fe93943d | |||
| 3258113ef8 | |||
| ebf3999cfe | |||
| a1ccbbb5b9 | |||
| 35072c40d8 | |||
| 5c51021388 | |||
| 95fd527515 | |||
| 113d851cea | |||
| 72f0c460f9 | |||
| 13ddd15b44 | |||
| c9e24aaf5f | |||
| 68c0ac0ffc | |||
| bebda275a9 | |||
| 287eaae850 | |||
| 7e59c3b9a7 | |||
| 38658a5b8c | |||
| 88c75b8672 | |||
| 17ab1e6830 | |||
| 1f45110e5f | |||
| 5401166a07 | |||
| bfa8188782 | |||
| e777a71784 | |||
| c13e91a0d0 | |||
| aac5d57352 | |||
| ceca13c7b6 | |||
| 2905470330 | |||
| 2c17033822 | |||
| 0a4cb9e9b1 | |||
| 096651f4c1 | |||
| 275a08506b | |||
| 4cd61cb381 | |||
| 9ad1147581 | |||
| 35e09def1b | |||
| 0469607a71 | |||
| d115d22ee6 | |||
| 8120ae621d | |||
| f873c2fa9f | |||
| c3ffbe2f42 | |||
| 55a0a39881 | |||
| 592215dd30 | |||
| ef0c2a2785 | |||
| 37979e452a | |||
| e9671bb727 | |||
| aa328bd591 | |||
| 188e4313f9 | |||
| df02c70e31 | |||
| 257f54b323 | |||
| fb4b5b2575 | |||
| 4e1251276d | |||
| a7b200dc57 | |||
| 8cadbae80e | |||
| c3bae49aae | |||
|
|
6fa4fc6149 | ||
| f1ffe1acaa | |||
| 5c9ddf7f00 | |||
| 431767a150 | |||
| 8ba4e442a6 | |||
| 2f8d19c267 | |||
| f2fd98f742 | |||
| 3ce35d6e81 | |||
| 796dbaa836 | |||
| 84b209ec7f | |||
| fa976b34dc | |||
| e7cda362b7 | |||
| a41a09c162 | |||
| e82f84f0ab | |||
| f1d387ceea | |||
| 3893d4d1f8 | |||
| cf7ac50faf | |||
| 3f6bf15554 | |||
| dac74829b4 | |||
| 94d6f213a0 | |||
| 8f2550ef61 | |||
| b622a1cc5e | |||
| c83a3c32c7 | |||
| e7dcf7f7e7 | |||
| 398785a2be | |||
| 05dba0f1f5 | |||
| 39dbd32b2e | |||
| 23a34a455a | |||
| 4308328b48 |
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
|
||||
|
||||
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
|
||||
|
||||
@@ -438,7 +438,6 @@ VertexOutput VS(TerrainVertexInput input)
|
||||
// Apply world position offset per-vertex
|
||||
#if USE_POSITION_OFFSET
|
||||
output.Geometry.WorldPosition += material.PositionOffset;
|
||||
output.Geometry.PrevWorldPosition += material.PositionOffset;
|
||||
output.Position = mul(float4(output.Geometry.WorldPosition, 1), ViewProjectionMatrix);
|
||||
#endif
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
Flax Engine is a high quality modern 3D game engine written in C++ and C#.
|
||||
From stunning graphics to powerful scripts, it's designed for fast workflow with many ready-to-use features waiting for you right now. To learn more see the website ([www.flaxengine.com](https://flaxengine.com)).
|
||||
|
||||
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Anyone is welcome to contribute or use the modified source in Flax-based games.
|
||||
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Documentation source is also available in a separate repository. Anyone is welcome to contribute or use the modified source in Flax-based games.
|
||||
|
||||
# Development
|
||||
|
||||
@@ -46,21 +46,26 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Install Visual Studio Code
|
||||
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||
* Ubuntu: `sudo apt install dotnet-sdk-8.0`
|
||||
* Fedora: `sudo dnf install dotnet-sdk-8.0`
|
||||
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
* Ubuntu: `sudo apt-get install git git-lfs`
|
||||
* Arch: `sudo pacman -S git git-lfs`
|
||||
* `git-lfs install`
|
||||
* Install the required packages:
|
||||
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
|
||||
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
|
||||
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
|
||||
* Install Clang compiler (version 6 or later):
|
||||
* Ubuntu: `sudo apt-get install clang lldb lld`
|
||||
* Fedora: `sudo dnf install clang llvm lldb lld`
|
||||
* Arch: `sudo pacman -S clang lldb lld`
|
||||
* Clone the repository (with LFS)
|
||||
* git-lfs clone https://github.com/FlaxEngine/FlaxEngine.git
|
||||
* Run `./GenerateProjectFiles.sh`
|
||||
* Open workspace with Visual Code
|
||||
* Build and run (configuration and task named `Flax|Editor.Linux.Development|x64`)
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace FlaxEditor.Content.Create
|
||||
/// <inheritdoc />
|
||||
public string ResultUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating wether a file can be created based on the current settings.
|
||||
/// </summary>
|
||||
public abstract bool CanBeCreated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this entry has settings to modify.
|
||||
/// </summary>
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace FlaxEditor.Content.Create
|
||||
Text = "Create",
|
||||
AnchorPreset = AnchorPresets.BottomRight,
|
||||
Offsets = new Margin(-ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight),
|
||||
Parent = this
|
||||
Parent = this,
|
||||
Enabled = entry.CanBeCreated,
|
||||
};
|
||||
createButton.Clicked += OnSubmit;
|
||||
var cancelButton = new Button
|
||||
@@ -68,7 +69,7 @@ namespace FlaxEditor.Content.Create
|
||||
Text = "Cancel",
|
||||
AnchorPreset = AnchorPresets.BottomRight,
|
||||
Offsets = new Margin(-ButtonsWidth - ButtonsMargin - ButtonsWidth - ButtonsMargin, ButtonsWidth, -ButtonsHeight - ButtonsMargin, ButtonsHeight),
|
||||
Parent = this
|
||||
Parent = this,
|
||||
};
|
||||
cancelButton.Clicked += OnCancel;
|
||||
|
||||
@@ -77,7 +78,7 @@ namespace FlaxEditor.Content.Create
|
||||
{
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||
Offsets = new Margin(2, 2, infoLabel.Bottom + 2, EditorHeight),
|
||||
Parent = this
|
||||
Parent = this,
|
||||
};
|
||||
|
||||
// Settings editor
|
||||
@@ -87,6 +88,7 @@ namespace FlaxEditor.Content.Create
|
||||
_dialogSize = new Float2(TotalWidth, panel.Bottom);
|
||||
|
||||
_settingsEditor.Select(_entry.Settings);
|
||||
_settingsEditor.Modified += () => createButton.Enabled = _entry.CanBeCreated;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace FlaxEditor.Content.Create
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class ParticleEmitterCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanBeCreated => true;
|
||||
|
||||
/// <summary>
|
||||
/// Types of the emitter templates that can be created.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace FlaxEditor.Content.Create
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class PrefabCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanBeCreated => _options.RootActorType != null;
|
||||
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
@@ -73,6 +76,9 @@ namespace FlaxEditor.Content.Create
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class WidgetCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanBeCreated => _options.RootControlType != null;
|
||||
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace FlaxEditor.Content.Create
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
internal class SettingsCreateEntry : CreateFileEntry
|
||||
{
|
||||
public override bool CanBeCreated => _options.Type != null;
|
||||
|
||||
internal class Options
|
||||
{
|
||||
[Tooltip("The settings type.")]
|
||||
|
||||
@@ -11,6 +11,9 @@ namespace FlaxEditor.Content.Create
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class VisualScriptCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanBeCreated => _options.BaseClass != null;
|
||||
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace FlaxEditor.Content.GUI
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, 0.3f, 3.0f);
|
||||
if (!Mathf.NearEqual(value, _viewScale))
|
||||
if (value != _viewScale)
|
||||
{
|
||||
_viewScale = value;
|
||||
ViewScaleChanged?.Invoke();
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace FlaxEditor.Content
|
||||
|
||||
if (data is DragDataFiles)
|
||||
return DragDropEffect.Copy;
|
||||
return _dragOverItems.Effect;
|
||||
return _dragOverItems?.Effect ?? DragDropEffect.None;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -65,6 +65,9 @@ namespace FlaxEditor.Content
|
||||
/// <seealso cref="FlaxEditor.Content.Create.CreateFileEntry" />
|
||||
public class GenericJsonCreateEntry : CreateFileEntry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanBeCreated => _options.Type != null;
|
||||
|
||||
/// <summary>
|
||||
/// The create options.
|
||||
/// </summary>
|
||||
|
||||
@@ -10,11 +10,9 @@ using FlaxEngine;
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>).
|
||||
/// Base class for shader source files.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentProxy" />
|
||||
[ContentContextMenu("New/Shader Source")]
|
||||
public class ShaderSourceProxy : ContentProxy
|
||||
public abstract class ShaderBaseProxy : ContentProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanCreate(ContentFolder targetLocation)
|
||||
@@ -29,6 +27,21 @@ namespace FlaxEditor.Content
|
||||
return targetLocation.ShortName == "Source" && prevTargetLocation.ShortName == "Shaders";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override EditorWindow Open(Editor editor, ContentItem item)
|
||||
{
|
||||
Editor.Instance.CodeEditing.OpenFile(item.Path);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>).
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentProxy" />
|
||||
[ContentContextMenu("New/Shader Source (.shader)")]
|
||||
public class ShaderSourceProxy : ShaderBaseProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Create(string outputPath, object arg)
|
||||
{
|
||||
@@ -44,13 +57,6 @@ namespace FlaxEditor.Content
|
||||
File.WriteAllText(outputPath, shaderTemplate, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override EditorWindow Open(Editor editor, ContentItem item)
|
||||
{
|
||||
Editor.Instance.CodeEditing.OpenFile(item.Path);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0x7542f5);
|
||||
|
||||
@@ -66,4 +72,33 @@ namespace FlaxEditor.Content
|
||||
return item is ShaderSourceItem;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Context proxy object for shader header files.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.ContentProxy" />
|
||||
[ContentContextMenu("New/Shader Header (.hlsl)")]
|
||||
public class ShaderHeaderProxy : ShaderBaseProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Create(string outputPath, object arg)
|
||||
{
|
||||
File.WriteAllText(outputPath, "\n", Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0x2545a5);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string FileExtension => "hlsl";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Shader Header";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsProxyFor(ContentItem item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -52,6 +53,16 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
/// <param name="nodes">The nodes to select</param>
|
||||
public void Select(List<SceneGraph.SceneGraphNode> nodes);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current selection.
|
||||
/// </summary>
|
||||
public List<SceneGraphNode> Selection { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indication of if the properties window is locked on specific objects.
|
||||
/// </summary>
|
||||
public bool LockSelection { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,6 +92,8 @@ namespace FlaxEditor.CustomEditors
|
||||
Offsets = Margin.Zero;
|
||||
Pivot = Float2.Zero;
|
||||
IsScrollable = true;
|
||||
Spacing = Utilities.Constants.UIMargin;
|
||||
Margin = new Margin(Utilities.Constants.UIMargin);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -95,7 +108,7 @@ namespace FlaxEditor.CustomEditors
|
||||
{
|
||||
FlaxEditor.Editor.LogWarning(ex);
|
||||
|
||||
// Refresh layout on errors to reduce lgo spam
|
||||
// Refresh layout on errors to reduce log spam
|
||||
_presenter.BuildLayout();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEditor.Windows.Assets;
|
||||
@@ -71,14 +70,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
|
||||
prefab.GetNestedObject(ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
|
||||
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
|
||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||
var panel = layout.UniformGrid();
|
||||
panel.CustomControl.Height = 20.0f;
|
||||
panel.CustomControl.SlotsVertically = 1;
|
||||
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
|
||||
{
|
||||
var targetPrefab = nestedPrefab ?? prefab;
|
||||
panel.CustomControl.SlotsHorizontally = 3;
|
||||
|
||||
|
||||
// Selecting actor prefab asset
|
||||
var selectPrefab = panel.Button("Select Prefab");
|
||||
selectPrefab.Button.Clicked += () =>
|
||||
@@ -133,35 +132,22 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var actor = (Actor)Values[0];
|
||||
var scriptType = TypeUtils.GetType(actor.TypeName);
|
||||
var item = scriptType.ContentItem;
|
||||
if (Presenter.Owner is PropertiesWindow propertiesWindow)
|
||||
if (Presenter.Owner != null)
|
||||
{
|
||||
var lockButton = cm.AddButton(propertiesWindow.LockObjects ? "Unlock" : "Lock");
|
||||
var lockButton = cm.AddButton(Presenter.Owner.LockSelection ? "Unlock" : "Lock");
|
||||
lockButton.ButtonClicked += button =>
|
||||
{
|
||||
propertiesWindow.LockObjects = !propertiesWindow.LockObjects;
|
||||
var owner = Presenter?.Owner;
|
||||
if (owner == null)
|
||||
return;
|
||||
owner.LockSelection = !owner.LockSelection;
|
||||
|
||||
// Reselect current selection
|
||||
if (!propertiesWindow.LockObjects && Editor.Instance.SceneEditing.SelectionCount > 0)
|
||||
if (!owner.LockSelection && owner.Selection.Count > 0)
|
||||
{
|
||||
var cachedSelection = Editor.Instance.SceneEditing.Selection.ToArray();
|
||||
Editor.Instance.SceneEditing.Select(null);
|
||||
Editor.Instance.SceneEditing.Select(cachedSelection);
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (Presenter.Owner is PrefabWindow prefabWindow)
|
||||
{
|
||||
var lockButton = cm.AddButton(prefabWindow.LockSelectedObjects ? "Unlock" : "Lock");
|
||||
lockButton.ButtonClicked += button =>
|
||||
{
|
||||
prefabWindow.LockSelectedObjects = !prefabWindow.LockSelectedObjects;
|
||||
|
||||
// Reselect current selection
|
||||
if (!prefabWindow.LockSelectedObjects && prefabWindow.Selection.Count > 0)
|
||||
{
|
||||
var cachedSelection = prefabWindow.Selection.ToList();
|
||||
prefabWindow.Select(null);
|
||||
prefabWindow.Select(cachedSelection);
|
||||
var cachedSelection = owner.Selection.ToList();
|
||||
owner.Select(null);
|
||||
owner.Select(cachedSelection);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -258,7 +244,17 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
else if (editor.Values[0] is SceneObject sceneObject)
|
||||
{
|
||||
node.TextColor = sceneObject.HasPrefabLink ? FlaxEngine.GUI.Style.Current.ProgressNormal : FlaxEngine.GUI.Style.Current.BackgroundSelected;
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name);
|
||||
if (editor.Values.Info != ScriptMemberInfo.Null)
|
||||
{
|
||||
if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute && !string.IsNullOrEmpty(editorDisplayAttribute.Name))
|
||||
node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})";
|
||||
else
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
|
||||
}
|
||||
else if (sceneObject is Actor actor)
|
||||
node.Text = $"{actor.Name} ({Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name)})";
|
||||
else
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(sceneObject.GetType().Name);
|
||||
}
|
||||
// Array Item
|
||||
else if (editor.ParentEditor is CollectionEditor)
|
||||
@@ -268,7 +264,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Common type
|
||||
else if (editor.Values.Info != ScriptMemberInfo.Null)
|
||||
{
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
|
||||
if (editor.Values.GetAttributes().FirstOrDefault(x => x is EditorDisplayAttribute) is EditorDisplayAttribute editorDisplayAttribute
|
||||
&& !string.IsNullOrEmpty(editorDisplayAttribute.Name)
|
||||
&& !editorDisplayAttribute.Name.Contains("_inline"))
|
||||
node.Text = $"{Utilities.Utils.GetPropertyNameUI(editorDisplayAttribute.Name)} ({Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name)})";
|
||||
else
|
||||
node.Text = Utilities.Utils.GetPropertyNameUI(editor.Values.Info.Name);
|
||||
}
|
||||
// Custom type
|
||||
else if (editor.Values[0] != null)
|
||||
@@ -316,7 +317,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var childEditor = editor.ChildrenEditors[i];
|
||||
|
||||
// Special case for root actor transformation (can be applied only in Prefab editor, not in Level)
|
||||
if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale")
|
||||
if (isActorEditorInLevel && childEditor.Values.Info.Name is "LocalPosition" or "LocalOrientation" or "LocalScale" or "Name")
|
||||
continue;
|
||||
|
||||
var child = ProcessDiff(childEditor, !isScriptEditorWithRefValue);
|
||||
@@ -361,13 +362,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
return result;
|
||||
}
|
||||
|
||||
private TreeNode CreateDiffTree(Actor actor, CustomEditorPresenter presenter, LayoutElementsContainer layout)
|
||||
{
|
||||
var actorNode = Editor.Instance.Scene.GetActorNode(actor);
|
||||
ValueContainer vc = new ValueContainer(ScriptMemberInfo.Null);
|
||||
vc.SetType(new ScriptType(actorNode.EditableObject.GetType()));
|
||||
vc.Add(actorNode.EditableObject);
|
||||
var editor = CustomEditorsUtil.CreateEditor(vc, null, false);
|
||||
editor.Initialize(presenter, layout, vc);
|
||||
var node = ProcessDiff(editor, false);
|
||||
layout.ClearLayout();
|
||||
foreach (var child in actor.Children)
|
||||
{
|
||||
var childNode = CreateDiffTree(child, presenter, layout);
|
||||
if (childNode == null)
|
||||
continue;
|
||||
if (node == null)
|
||||
node = CreateDiffNode(editor);
|
||||
node.AddChild(childNode);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void ViewChanges(Control target, Float2 targetLocation)
|
||||
{
|
||||
// Build a tree out of modified properties
|
||||
var rootNode = ProcessDiff(this, false);
|
||||
var thisActor = (Actor)Values[0];
|
||||
var rootActor = thisActor.IsPrefabRoot ? thisActor : thisActor.GetPrefabRoot();
|
||||
var presenter = new CustomEditorPresenter(null);
|
||||
var layout = new CustomElementsContainer<ContainerControl>();
|
||||
var rootNode = CreateDiffTree(rootActor, presenter, layout);
|
||||
|
||||
// Skip if no changes detected
|
||||
if (rootNode == null || rootNode.ChildrenCount == 0)
|
||||
if (rootNode == null)
|
||||
{
|
||||
var cm1 = new ContextMenu();
|
||||
cm1.AddButton("No changes detected");
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = playbackGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var paintValue = new ReadOnlyValueContainer(new ScriptType(typeof(ClothPaintingGizmoMode)), _gizmoMode);
|
||||
paintGroup.Object(paintValue);
|
||||
{
|
||||
var grid = paintGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = paintGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEngine;
|
||||
@@ -16,6 +15,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
private int _layersCount;
|
||||
private List<CheckBox> _checkBoxes;
|
||||
private VerticalPanel _upperRightCell;
|
||||
private VerticalPanel _bottomLeftCell;
|
||||
private UniformGridPanel _grid;
|
||||
private Border _horizontalHighlight;
|
||||
private Border _verticalHighlight;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.InlineIntoParent;
|
||||
@@ -37,12 +41,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = panel,
|
||||
};
|
||||
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
_horizontalHighlight = new Border()
|
||||
{
|
||||
Parent = panel,
|
||||
BorderColor = style.Foreground,
|
||||
BorderWidth = 1.0f,
|
||||
Visible = false,
|
||||
};
|
||||
|
||||
_verticalHighlight = new Border()
|
||||
{
|
||||
Parent = panel,
|
||||
BorderColor = style.Foreground,
|
||||
BorderWidth = 1.0f,
|
||||
Visible = false,
|
||||
};
|
||||
|
||||
var upperLeftCell = new Label
|
||||
{
|
||||
Parent = gridPanel,
|
||||
};
|
||||
|
||||
var upperRightCell = new VerticalPanel
|
||||
_upperRightCell = new VerticalPanel
|
||||
{
|
||||
ClipChildren = false,
|
||||
Pivot = new Float2(0.00001f, 0.0f),
|
||||
@@ -54,7 +75,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = gridPanel,
|
||||
};
|
||||
|
||||
var bottomLeftCell = new VerticalPanel
|
||||
_bottomLeftCell = new VerticalPanel
|
||||
{
|
||||
Pivot = Float2.Zero,
|
||||
Spacing = 0,
|
||||
@@ -63,7 +84,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
Parent = gridPanel,
|
||||
};
|
||||
|
||||
var grid = new UniformGridPanel(0)
|
||||
_grid = new UniformGridPanel(0)
|
||||
{
|
||||
SlotsHorizontally = layersCount,
|
||||
SlotsVertically = layersCount,
|
||||
@@ -74,13 +95,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
int layerIndex = 0;
|
||||
for (; layerIndex < layerNames.Length; layerIndex++)
|
||||
{
|
||||
upperRightCell.AddChild(new Label
|
||||
_upperRightCell.AddChild(new Label
|
||||
{
|
||||
Height = labelsHeight,
|
||||
Text = layerNames[layerNames.Length - layerIndex - 1],
|
||||
HorizontalAlignment = TextAlignment.Near,
|
||||
});
|
||||
bottomLeftCell.AddChild(new Label
|
||||
_bottomLeftCell.AddChild(new Label
|
||||
{
|
||||
Height = labelsHeight,
|
||||
Text = layerNames[layerIndex],
|
||||
@@ -90,13 +111,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
for (; layerIndex < layersCount; layerIndex++)
|
||||
{
|
||||
string name = "Layer " + layerIndex;
|
||||
upperRightCell.AddChild(new Label
|
||||
_upperRightCell.AddChild(new Label
|
||||
{
|
||||
Height = labelsHeight,
|
||||
Text = name,
|
||||
HorizontalAlignment = TextAlignment.Near,
|
||||
});
|
||||
bottomLeftCell.AddChild(new Label
|
||||
_bottomLeftCell.AddChild(new Label
|
||||
{
|
||||
Height = labelsHeight,
|
||||
Text = name,
|
||||
@@ -118,7 +139,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var box = new CheckBox(0, 0, true)
|
||||
{
|
||||
Tag = new Float2(_layersCount - column - 1, row),
|
||||
Parent = grid,
|
||||
Parent = _grid,
|
||||
Checked = GetBit(column, row),
|
||||
};
|
||||
box.StateChanged += OnCheckBoxChanged;
|
||||
@@ -126,7 +147,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
}
|
||||
for (; column < layersCount; column++)
|
||||
{
|
||||
grid.AddChild(new Label());
|
||||
_grid.AddChild(new Label());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,6 +162,18 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
int selectedColumn = -1;
|
||||
int selectedRow = -1;
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
bool mouseOverGrid = _grid.IsMouseOver;
|
||||
|
||||
// Only hide highlights if mouse is not over the grid to reduce flickering
|
||||
if (!mouseOverGrid)
|
||||
{
|
||||
_horizontalHighlight.Visible = false;
|
||||
_verticalHighlight.Visible = false;
|
||||
}
|
||||
|
||||
// Sync check boxes
|
||||
for (int i = 0; i < _checkBoxes.Count; i++)
|
||||
{
|
||||
@@ -148,6 +181,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
int column = (int)((Float2)box.Tag).X;
|
||||
int row = (int)((Float2)box.Tag).Y;
|
||||
box.Checked = GetBit(column, row);
|
||||
|
||||
if (box.IsMouseOver)
|
||||
{
|
||||
selectedColumn = column;
|
||||
selectedRow = row;
|
||||
|
||||
_horizontalHighlight.X = _grid.X - _bottomLeftCell.Width;
|
||||
_horizontalHighlight.Y = _grid.Y + box.Y;
|
||||
_horizontalHighlight.Width = _bottomLeftCell.Width + box.Width + box.X;
|
||||
_horizontalHighlight.Height = box.Height;
|
||||
_horizontalHighlight.Visible = true;
|
||||
|
||||
_verticalHighlight.X = _grid.X + box.X;
|
||||
_verticalHighlight.Y = _grid.Y - _upperRightCell.Height;
|
||||
_verticalHighlight.Width = box.Width;
|
||||
_verticalHighlight.Height = _upperRightCell.Height + box.Height + box.Y;
|
||||
_verticalHighlight.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _checkBoxes.Count; i++)
|
||||
{
|
||||
var box = _checkBoxes[i];
|
||||
int column = (int)((Float2)box.Tag).X;
|
||||
int row = (int)((Float2)box.Tag).Y;
|
||||
|
||||
if (!mouseOverGrid)
|
||||
box.ImageColor = style.BorderSelected;
|
||||
else if (selectedColumn > -1 && selectedRow > -1)
|
||||
{
|
||||
bool isRowOrColumn = column == selectedColumn || row == selectedRow;
|
||||
box.ImageColor = style.BorderSelected * (isRowOrColumn ? 1.2f : 0.75f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,12 +92,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
// Update add button
|
||||
var update = group.Button("Update").Button;
|
||||
group.Space(0);
|
||||
update.TooltipText = "Refreshes the dashboard statistics";
|
||||
update.Height = 16.0f;
|
||||
update.Clicked += RebuildLayout;
|
||||
|
||||
// New locale add button
|
||||
var addLocale = group.Button("Add Locale...").Button;
|
||||
group.Space(0);
|
||||
addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables";
|
||||
addLocale.Height = 16.0f;
|
||||
addLocale.ButtonClicked += delegate(Button button)
|
||||
@@ -167,12 +169,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
// Export button
|
||||
var exportLocalization = group.Button("Export...").Button;
|
||||
group.Space(0);
|
||||
exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
|
||||
exportLocalization.Height = 16.0f;
|
||||
exportLocalization.Clicked += () => Export(tableEntries, allKeys);
|
||||
|
||||
// Find localized strings in code button
|
||||
var findStringsCode = group.Button("Find localized strings in code").Button;
|
||||
group.Space(0);
|
||||
findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files";
|
||||
findStringsCode.Height = 16.0f;
|
||||
findStringsCode.Clicked += delegate
|
||||
@@ -186,12 +190,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);
|
||||
|
||||
@@ -54,7 +54,8 @@ public class ModelPrefabEditor : GenericEditor
|
||||
}
|
||||
|
||||
// Creates the import path UI
|
||||
Utilities.Utils.CreateImportPathUI(layout, modelPrefab.ImportPath, false);
|
||||
var group = layout.Group("Import Path");
|
||||
Utilities.Utils.CreateImportPathUI(group, modelPrefab.ImportPath);
|
||||
|
||||
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
|
||||
_reimportButton = button.Button;
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = playbackGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (ragdoll.Parent is AnimatedModel animatedModel && animatedModel.SkinnedModel)
|
||||
{
|
||||
// Builder
|
||||
var grid = editorGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = editorGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
@@ -53,7 +53,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (Presenter.Owner != null)
|
||||
{
|
||||
// Selection
|
||||
var grid = editorGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = editorGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -93,8 +94,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Add info box
|
||||
if (IsSingleObject && Values[0] is RigidBody && Editor.IsPlayMode)
|
||||
{
|
||||
_infoLabel = layout.Label(string.Empty).Label;
|
||||
var group = layout.Group("Info");
|
||||
_infoLabel = group.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
_infoLabel.Margin = new Margin(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = playbackGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -682,7 +682,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
private CustomElementsContainer<UniformGridPanel> UniformGridTwoByOne(LayoutElementsContainer cont)
|
||||
{
|
||||
var grid = cont.CustomContainer<UniformGridPanel>();
|
||||
var grid = cont.UniformGrid();
|
||||
grid.CustomControl.SlotsHorizontally = 2;
|
||||
grid.CustomControl.SlotsVertically = 1;
|
||||
grid.CustomControl.SlotPadding = Margin.Zero;
|
||||
|
||||
@@ -41,13 +41,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
CheckLayout(ug);
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
@@ -75,11 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
base.Initialize(layout);
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
CheckLayout(ug);
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
@@ -136,13 +128,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
CheckLayout(ug);
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
@@ -203,5 +191,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_linkButton.TooltipText = LinkValues ? "Unlinks scale components from uniform scaling" : "Links scale components for uniform scaling";
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckLayout(UniformGridPanel ug)
|
||||
{
|
||||
// Enlarge to fix border visibility
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing += new Float2(2);
|
||||
ug.SlotPadding += new Margin(0, 0, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,10 +642,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (_canResize && !_readOnly)
|
||||
{
|
||||
var panel = dragArea.HorizontalPanel();
|
||||
panel.Panel.Size = new Float2(0, 20);
|
||||
panel.Panel.Margin = new Margin(2);
|
||||
panel.Panel.Size = new Float2(0, 18);
|
||||
panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
|
||||
|
||||
var removeButton = panel.Button("-", "Remove last item");
|
||||
var removeButton = panel.Button("-", "Remove the last item");
|
||||
removeButton.Button.Size = new Float2(16, 16);
|
||||
removeButton.Button.Enabled = size > _minCount;
|
||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
@@ -656,7 +656,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Resize(Count - 1);
|
||||
};
|
||||
|
||||
var addButton = panel.Button("+", "Add new item");
|
||||
var addButton = panel.Button("+", "Add a new item");
|
||||
addButton.Button.Size = new Float2(16, 16);
|
||||
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
float trackBallSize = 80.0f;
|
||||
float trackBallSize = 100f;
|
||||
float margin = 4.0f;
|
||||
|
||||
// Panel
|
||||
@@ -50,7 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Scale editor
|
||||
{
|
||||
var grid = masterPanel.CustomContainer<UniformGridPanel>();
|
||||
var grid = masterPanel.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.SlotPadding = new Margin(4, 2, 2, 2);
|
||||
gridControl.ClipChildren = false;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public sealed class LocalizedStringEditor : GenericEditor
|
||||
{
|
||||
private TextBoxElement _idElement, _valueElement;
|
||||
private Button _viewStringButton;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
@@ -70,6 +71,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
};
|
||||
addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
|
||||
addString.ButtonClicked += OnAddStringClicked;
|
||||
|
||||
var viewString = new Button
|
||||
{
|
||||
Visible = false,
|
||||
Width = 16.0f,
|
||||
BackgroundColor = Color.White,
|
||||
BackgroundColorHighlighted = Color.Gray,
|
||||
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Search12),
|
||||
TooltipText = "Find localized text in Localized String Table asset for the current locale...",
|
||||
Parent = valueElement.TextBox,
|
||||
};
|
||||
viewString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
|
||||
viewString.LocalX -= 16.0f;
|
||||
viewString.ButtonClicked += OnViewStringClicked;
|
||||
_viewStringButton = viewString;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -80,6 +96,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (_valueElement != null)
|
||||
{
|
||||
_valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text);
|
||||
_viewStringButton.Visible = !string.IsNullOrEmpty(_valueElement.TextBox.WatermarkText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,14 +109,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_valueElement = null;
|
||||
}
|
||||
|
||||
private void OnSelectStringClicked(Button button)
|
||||
private bool GetSettings(out LocalizationSettings settings)
|
||||
{
|
||||
var settings = GameSettings.Load<LocalizationSettings>();
|
||||
settings = GameSettings.Load<LocalizationSettings>();
|
||||
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
|
||||
{
|
||||
MessageBox.Show("No valid localization settings setup.");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnSelectStringClicked(Button button)
|
||||
{
|
||||
if (GetSettings(out var settings))
|
||||
return;
|
||||
Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked");
|
||||
var allKeys = new HashSet<string>();
|
||||
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
|
||||
@@ -136,6 +160,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
menu.Hide();
|
||||
_idElement.TextBox.SetTextAsUser(after[0].Text);
|
||||
_valueElement.TextBox.SetTextAsUser(string.Empty);
|
||||
}
|
||||
};
|
||||
searchBox.TextChanged += delegate
|
||||
@@ -158,12 +183,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
private void OnAddStringClicked(Button button)
|
||||
{
|
||||
var settings = GameSettings.Load<LocalizationSettings>();
|
||||
if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
|
||||
{
|
||||
MessageBox.Show("No valid localization settings setup.");
|
||||
if (GetSettings(out var settings))
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked");
|
||||
var allKeys = new HashSet<string>();
|
||||
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
|
||||
@@ -231,5 +252,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_idElement.TextBox.SetTextAsUser(newKey);
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private void OnViewStringClicked(Button button)
|
||||
{
|
||||
if (GetSettings(out var settings))
|
||||
return;
|
||||
var id = _idElement.TextBox.Text;
|
||||
var value = _valueElement.TextBox.WatermarkText;
|
||||
for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
|
||||
{
|
||||
var table = settings.LocalizedStringTables[i];
|
||||
if (table && !table.WaitForLoaded())
|
||||
{
|
||||
var entries = table.Entries;
|
||||
if (entries.TryGetValue(id, out var messages))
|
||||
{
|
||||
if (messages.Length != 0 && messages[0] == value)
|
||||
{
|
||||
Editor.Instance.ContentEditing.Open(table);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageBox.Show("Unable to find localized string table.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
|
||||
_element = layout.TextBox(isMultiLine);
|
||||
_defaultWatermarkColor = _element.TextBox.WatermarkTextColor;
|
||||
_watermarkColor = _defaultWatermarkColor = _element.TextBox.WatermarkTextColor;
|
||||
if (watermarkAttribute is WatermarkAttribute watermark)
|
||||
{
|
||||
_watermarkText = watermark.WatermarkText;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -220,7 +220,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -469,7 +469,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -783,7 +783,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -163,7 +163,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
@@ -274,7 +274,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var grid = layout.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = TextBox.DefaultHeight;
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
ArrowImageClosed = new SpriteBrush(Style.Current.ArrowRight),
|
||||
ArrowImageOpened = new SpriteBrush(Style.Current.ArrowDown),
|
||||
EnableDropDownIcon = true,
|
||||
ItemsMargin = new Margin(7, 7, 3, 3),
|
||||
ItemsMargin = new Margin(Utilities.Constants.UIMargin),
|
||||
ItemsSpacing = Utilities.Constants.UIMargin,
|
||||
HeaderHeight = 18.0f,
|
||||
EnableContainmentLines = true,
|
||||
};
|
||||
|
||||
@@ -20,13 +20,6 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
/// </summary>
|
||||
public const int SplitterSize = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The splitter margin (in pixels).
|
||||
/// </summary>
|
||||
public const int SplitterMargin = 4;
|
||||
|
||||
private const int SplitterSizeHalf = SplitterSize / 2;
|
||||
|
||||
private PropertiesListElement _element;
|
||||
private float _splitterValue;
|
||||
private Rectangle _splitterRect;
|
||||
@@ -65,16 +58,18 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
/// <param name="element">The element.</param>
|
||||
public PropertiesList(PropertiesListElement element)
|
||||
{
|
||||
ClipChildren = false;
|
||||
_element = element;
|
||||
_splitterValue = 0.4f;
|
||||
BottomMargin = TopMargin = RightMargin = SplitterMargin;
|
||||
Margin = new Margin();
|
||||
Spacing = Utilities.Constants.UIMargin;
|
||||
UpdateSplitRect();
|
||||
}
|
||||
|
||||
private void UpdateSplitRect()
|
||||
{
|
||||
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSizeHalf, 0.0f, Width), 0, SplitterSize, Height);
|
||||
LeftMargin = _splitterValue * Width + SplitterMargin;
|
||||
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSize * 0.5f, 0.0f, Width), 0, SplitterSize, Height);
|
||||
LeftMargin = _splitterValue * Width + _spacing;
|
||||
}
|
||||
|
||||
private void StartTracking()
|
||||
@@ -222,23 +217,33 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutAfterChildren()
|
||||
{
|
||||
// Sort controls from up to down into two columns: one for labels and one for the rest of the stuff
|
||||
|
||||
// Place non-label controls from top to down
|
||||
float y = _margin.Top;
|
||||
float w = Width - _margin.Width;
|
||||
bool firstItem = true;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
Control c = _children[i];
|
||||
if (!(c is PropertyNameLabel))
|
||||
{
|
||||
var h = c.Height;
|
||||
c.Bounds = new Rectangle(_margin.Left, y + _spacing, w, h);
|
||||
var rect = new Rectangle(_margin.Left, y, w, c.Height);
|
||||
if (c.Visible)
|
||||
{
|
||||
if (firstItem)
|
||||
firstItem = false;
|
||||
else
|
||||
rect.Y += _spacing;
|
||||
}
|
||||
else if (!firstItem)
|
||||
rect.Y += _spacing;
|
||||
c.Bounds = rect;
|
||||
if (c.Visible)
|
||||
y = c.Bottom;
|
||||
}
|
||||
}
|
||||
y += _margin.Bottom;
|
||||
|
||||
// Place labels accordingly to their respective controls placement
|
||||
float namesWidth = _splitterValue * Width;
|
||||
int count = _element.Labels.Count;
|
||||
float[] yStarts = new float[count + 1];
|
||||
@@ -271,7 +276,9 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
{
|
||||
var label = _element.Labels[i];
|
||||
|
||||
var rect = new Rectangle(0, yStarts[i] + 1, namesWidth, yStarts[i + 1] - yStarts[i] - 2);
|
||||
var rect = new Rectangle(0, yStarts[i], namesWidth, yStarts[i + 1] - yStarts[i]);
|
||||
if (i != count - 1)
|
||||
rect.Height -= _spacing;
|
||||
//label.Parent = this;
|
||||
label.Bounds = rect;
|
||||
}
|
||||
|
||||
@@ -202,6 +202,17 @@ namespace FlaxEditor.CustomEditors
|
||||
return element;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds new uniform grid control.
|
||||
/// </summary>
|
||||
/// <returns>The created element.</returns>
|
||||
public CustomElementsContainer<UniformGridPanel> UniformGrid()
|
||||
{
|
||||
var grid = CustomContainer<UniformGridPanel>();
|
||||
grid.CustomControl.SlotSpacing = new Float2(Utilities.Constants.UIMargin);
|
||||
return grid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds new custom element.
|
||||
/// </summary>
|
||||
|
||||
@@ -670,6 +670,8 @@ namespace FlaxEditor
|
||||
{
|
||||
FlaxEngine.Networking.NetworkManager.Stop(); // Shutdown any multiplayer from playmode
|
||||
PlayModeEnding?.Invoke();
|
||||
for (int i = 0; i < _modules.Count; i++)
|
||||
_modules[i].OnPlayEnding();
|
||||
}
|
||||
|
||||
internal void OnPlayEnd()
|
||||
@@ -1031,6 +1033,8 @@ namespace FlaxEditor
|
||||
{
|
||||
Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box);
|
||||
BoundingSphere.FromBox(ref box, out sphere);
|
||||
if (sphere == BoundingSphere.Empty)
|
||||
sphere = new BoundingSphere(actor.Position, sphere.Radius);
|
||||
sphere.Radius = Math.Max(sphere.Radius, 15.0f);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -299,6 +299,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
// Select asset
|
||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
}
|
||||
}
|
||||
else if (Button1Rect.Contains(location))
|
||||
@@ -312,6 +313,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
// Select asset
|
||||
Editor.Instance.Windows.ContentWin.Select(Validator.SelectedItem);
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
}
|
||||
else if (Button3Rect.Contains(location))
|
||||
{
|
||||
|
||||
@@ -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) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -121,7 +124,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>
|
||||
@@ -256,7 +259,9 @@ 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);
|
||||
@@ -265,6 +270,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
_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;
|
||||
@@ -285,6 +296,17 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
private static void ForceDefocus(ContainerControl c)
|
||||
{
|
||||
foreach (var cc in c.Children)
|
||||
{
|
||||
if (cc.ContainsFocus)
|
||||
cc.Defocus();
|
||||
if (cc is ContainerControl ccc)
|
||||
ForceDefocus(ccc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide popup menu and all child menus.
|
||||
/// </summary>
|
||||
@@ -299,6 +321,9 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Close child
|
||||
HideChild();
|
||||
|
||||
// Force defocus
|
||||
ForceDefocus(this);
|
||||
|
||||
// Unlink from window
|
||||
Parent = null;
|
||||
|
||||
@@ -426,6 +451,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;
|
||||
@@ -439,6 +475,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnWindowLostFocus()
|
||||
{
|
||||
@@ -537,7 +574,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Let root context menu to check if none of the popup windows
|
||||
if (_parentCM == null && UseVisibilityControl && !IsForeground)
|
||||
{
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
if (!IsMouseOver)
|
||||
Hide();
|
||||
#else
|
||||
Hide();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,545 +0,0 @@
|
||||
// Copyright (c) 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.Selection;
|
||||
Window.GUI.AddChild<DragVisuals>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resize proxy
|
||||
Window.ClientSize = initSize;
|
||||
}
|
||||
|
||||
InitHitProxy();
|
||||
}
|
||||
|
||||
private sealed class DragVisuals : Control
|
||||
{
|
||||
public DragVisuals()
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll;
|
||||
Offsets = Margin.Zero;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.SelectionBorder);
|
||||
}
|
||||
}
|
||||
|
||||
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.Selection;
|
||||
win.GUI.AddChild<DragVisuals>();
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
return;
|
||||
|
||||
// Create docking hint window
|
||||
DockHintWindow.Create(this);
|
||||
WindowDragHelper.StartDragging(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,18 +71,18 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.Title = title;
|
||||
settings.Size = size;
|
||||
settings.Position = location;
|
||||
settings.MinimumSize = new Float2(1);
|
||||
settings.MinimumSize = new Float2(200, 150);
|
||||
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
|
||||
|
||||
458
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
458
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
@@ -0,0 +1,458 @@
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any windows are being dragged.
|
||||
/// </summary>
|
||||
public static bool IsDragActive { get; private set; }
|
||||
|
||||
private WindowDragHelper(FloatWindowDockPanel toMove, Window dragSourceWindow)
|
||||
{
|
||||
IsDragActive = true;
|
||||
_toMove = toMove;
|
||||
_toSet = DockState.Float;
|
||||
var window = toMove.Window.Window;
|
||||
|
||||
// Bind events
|
||||
FlaxEngine.Scripting.Update += OnUpdate;
|
||||
window.MouseUp += OnMouseUp;
|
||||
|
||||
// Update rectangles
|
||||
UpdateRects(Platform.MousePosition);
|
||||
|
||||
// Ensure the dragged window stays on top of every other window
|
||||
window.IsAlwaysOnTop = true;
|
||||
|
||||
_dragSourceWindow = dragSourceWindow;
|
||||
if (_dragSourceWindow != null) // Detaching a tab from existing window
|
||||
{
|
||||
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
|
||||
|
||||
_dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows
|
||||
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dragOffset = window.MousePosition;
|
||||
window.DoDragDrop(window.Title, _dragOffset, window);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
IsDragActive = false;
|
||||
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 sealed class DragVisuals : Control
|
||||
{
|
||||
public DragVisuals()
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll;
|
||||
Offsets = Margin.Zero;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.SelectionBorder);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DragVisuals hintControl = _toDock.AddChild<DragVisuals>();
|
||||
hintControl.Size = new Float2(HintControlSize);
|
||||
hintControl.BackgroundColor = Style.Current.Selection.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.Selection.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintLeft)
|
||||
{
|
||||
_dockHintLeft.Size = new Float2(HintControlSize);
|
||||
_dockHintLeft.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintRight)
|
||||
{
|
||||
_dockHintRight.Size = new Float2(HintControlSize);
|
||||
_dockHintRight.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintUp)
|
||||
{
|
||||
_dockHintUp.Size = new Float2(HintControlSize);
|
||||
_dockHintUp.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
||||
}
|
||||
if (hoveredHintControl != _dockHintCenter)
|
||||
{
|
||||
_dockHintCenter.Size = new Float2(HintControlSize);
|
||||
_dockHintCenter.BackgroundColor = Style.Current.Selection.AlphaMultiplied(0.6f);
|
||||
}
|
||||
|
||||
if (_toSet != DockState.Float)
|
||||
{
|
||||
if (hoveredHintControl != null)
|
||||
{
|
||||
hoveredHintControl.BackgroundColor = Style.Current.Selection.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathd.NearEqual(_min, value))
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
@@ -58,7 +58,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathd.NearEqual(_max, value))
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_min, value))
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_max, value))
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI.Input
|
||||
set
|
||||
{
|
||||
value = Mathf.Clamp(value, Minimum, Maximum);
|
||||
if (!Mathf.NearEqual(value, _value))
|
||||
if (value != _value)
|
||||
{
|
||||
_value = value;
|
||||
|
||||
@@ -311,7 +311,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _min;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_min, value))
|
||||
if (_min != value)
|
||||
{
|
||||
if (value > _max)
|
||||
throw new ArgumentException();
|
||||
@@ -330,7 +330,7 @@ namespace FlaxEditor.GUI.Input
|
||||
get => _max;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_max, value))
|
||||
if (_max != value)
|
||||
{
|
||||
if (value < _min)
|
||||
throw new ArgumentException();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -563,8 +563,17 @@ namespace FlaxEditor.GUI
|
||||
case KeyboardKeys.Escape:
|
||||
Hide();
|
||||
return true;
|
||||
case KeyboardKeys.Backspace:
|
||||
// Alow the user to quickly focus the searchbar
|
||||
if (_searchBox != null && !_searchBox.IsFocused)
|
||||
{
|
||||
_searchBox.Focus();
|
||||
_searchBox.SelectAll();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case KeyboardKeys.ArrowDown:
|
||||
{
|
||||
case KeyboardKeys.ArrowUp:
|
||||
if (RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Focus search box if nothing is focused
|
||||
@@ -572,45 +581,33 @@ namespace FlaxEditor.GUI
|
||||
return true;
|
||||
}
|
||||
|
||||
// Focus the first visible item or then next one
|
||||
// Get the next item
|
||||
var items = GetVisibleItems();
|
||||
var focusedIndex = items.IndexOf(focusedItem);
|
||||
if (focusedIndex == -1)
|
||||
focusedIndex = -1;
|
||||
if (focusedIndex + 1 < items.Count)
|
||||
{
|
||||
var item = items[focusedIndex + 1];
|
||||
item.Focus();
|
||||
_scrollPanel.ScrollViewTo(item);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KeyboardKeys.ArrowUp:
|
||||
if (focusedItem != null)
|
||||
{
|
||||
// Focus the previous visible item or the search box
|
||||
var items = GetVisibleItems();
|
||||
var focusedIndex = items.IndexOf(focusedItem);
|
||||
if (focusedIndex == 0)
|
||||
{
|
||||
_searchBox?.Focus();
|
||||
}
|
||||
else if (focusedIndex > 0)
|
||||
{
|
||||
var item = items[focusedIndex - 1];
|
||||
item.Focus();
|
||||
_scrollPanel.ScrollViewTo(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
int delta = key == KeyboardKeys.ArrowDown ? -1 : 1;
|
||||
int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, items.Count - 1);
|
||||
var nextItem = items[nextIndex];
|
||||
|
||||
// Focus the next item
|
||||
nextItem.Focus();
|
||||
_scrollPanel.ScrollViewTo(nextItem);
|
||||
return true;
|
||||
case KeyboardKeys.Return:
|
||||
if (focusedItem != null)
|
||||
{
|
||||
OnClickItem(focusedItem);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select first item if no item is focused (most likely to be the best result), saves the user from pressing arrow down first
|
||||
var visibleItems = GetVisibleItems();
|
||||
if (visibleItems.Count > 0)
|
||||
{
|
||||
OnClickItem(visibleItems[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -266,6 +268,19 @@ namespace FlaxEditor.GUI
|
||||
return AddChild(new MainMenuButton(text));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or adds a button.
|
||||
/// </summary>
|
||||
/// <param name="text">The button text</param>
|
||||
/// <returns>The existing or created button control.</returns>
|
||||
public MainMenuButton GetOrAddButton(string text)
|
||||
{
|
||||
MainMenuButton result = GetButton(text);
|
||||
if (result == null)
|
||||
result = AddButton(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the button.
|
||||
/// </summary>
|
||||
@@ -291,7 +306,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 +336,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Icon
|
||||
@@ -349,7 +364,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Buttons
|
||||
@@ -367,7 +382,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;
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace FlaxEditor.GUI.Tabs
|
||||
if (EnabledInHierarchy && Tab.Enabled)
|
||||
{
|
||||
Tabs.SelectedTab = Tab;
|
||||
Tab.PerformLayout(true);
|
||||
Tabs.Focus();
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -122,6 +122,14 @@ namespace FlaxEditor.GUI
|
||||
return this;
|
||||
}
|
||||
|
||||
private void OnClicked()
|
||||
{
|
||||
if (AutoCheck)
|
||||
Checked = !Checked;
|
||||
Clicked?.Invoke();
|
||||
(Parent as ToolStrip)?.OnButtonClicked(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
@@ -196,11 +204,7 @@ namespace FlaxEditor.GUI
|
||||
if (button == MouseButton.Left && _primaryMouseDown)
|
||||
{
|
||||
_primaryMouseDown = false;
|
||||
if (AutoCheck)
|
||||
Checked = !Checked;
|
||||
Clicked?.Invoke();
|
||||
(Parent as ToolStrip)?.OnButtonClicked(this);
|
||||
|
||||
OnClicked();
|
||||
return true;
|
||||
}
|
||||
if (button == MouseButton.Right && _secondaryMouseDown)
|
||||
@@ -215,6 +219,18 @@ namespace FlaxEditor.GUI
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
OnClicked();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace FlaxEditor.GUI.Tree
|
||||
private readonly bool _supportMultiSelect;
|
||||
private Margin _margin;
|
||||
private bool _autoSize = true;
|
||||
private bool _deferLayoutUpdate = false;
|
||||
|
||||
/// <summary>
|
||||
/// The TreeNode that is being dragged over. This could have a value when not dragging.
|
||||
@@ -66,6 +67,16 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// Gets the first selected node or null.
|
||||
/// </summary>
|
||||
public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null;
|
||||
|
||||
/// <summary>
|
||||
/// Allow nodes to Draw the root tree line.
|
||||
/// </summary>
|
||||
public bool DrawRootTreeLine = true;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the deferred layout operation was performed.
|
||||
/// </summary>
|
||||
public event Action AfterDeferredLayout;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the margin for the child tree nodes.
|
||||
@@ -353,9 +364,26 @@ namespace FlaxEditor.GUI.Tree
|
||||
BulkSelectUpdateExpanded(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PerformLayout(bool force = false)
|
||||
{
|
||||
if (_isLayoutLocked && !force)
|
||||
return;
|
||||
|
||||
// In case the tree was fully expanded or collapsed along its children, avoid calculating the layout multiple times for each child
|
||||
_deferLayoutUpdate = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (_deferLayoutUpdate)
|
||||
{
|
||||
base.PerformLayout();
|
||||
AfterDeferredLayout?.Invoke();
|
||||
_deferLayoutUpdate = false;
|
||||
}
|
||||
|
||||
var node = SelectedNode;
|
||||
|
||||
// Check if has focus and if any node is focused and it isn't a root
|
||||
|
||||
@@ -760,20 +760,21 @@ namespace FlaxEditor.GUI.Tree
|
||||
// Show tree guidelines
|
||||
if (Editor.Instance.Options.Options.Interface.ShowTreeLines)
|
||||
{
|
||||
TreeNode parentNode = Parent as TreeNode;
|
||||
ContainerControl parent = Parent;
|
||||
TreeNode parentNode = parent as TreeNode;
|
||||
bool thisNodeIsLast = false;
|
||||
while (parentNode != null && parentNode != ParentTree.Children[0])
|
||||
while (parentNode != null && (parentNode != tree.Children[0] || tree.DrawRootTreeLine))
|
||||
{
|
||||
float bottomOffset = 0;
|
||||
float topOffset = 0;
|
||||
|
||||
if (Parent == parentNode && this == Parent.Children[0])
|
||||
if (parent == parentNode && this == parent.Children[0])
|
||||
topOffset = 2;
|
||||
|
||||
if (thisNodeIsLast && parentNode.Children.Count == 1)
|
||||
bottomOffset = topOffset != 0 ? 4 : 2;
|
||||
|
||||
if (Parent == parentNode && this == Parent.Children[Parent.Children.Count - 1] && !_opened)
|
||||
if (parent == parentNode && this == parent.Children[^1] && !_opened)
|
||||
{
|
||||
thisNodeIsLast = true;
|
||||
bottomOffset = topOffset != 0 ? 4 : 2;
|
||||
@@ -784,6 +785,8 @@ namespace FlaxEditor.GUI.Tree
|
||||
if (_iconCollaped.IsValid)
|
||||
leftOffset += 18;
|
||||
var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset);
|
||||
if (HasAnyVisibleChild && CustomArrowRect.HasValue && CustomArrowRect.Value.Intersects(lineRect1))
|
||||
lineRect1 = Rectangle.Empty; // Skip drawing line if it's overlapping the arrow rectangle
|
||||
Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground);
|
||||
parentNode = parentNode.Parent as TreeNode;
|
||||
}
|
||||
|
||||
@@ -402,10 +402,11 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
||||
break;
|
||||
}
|
||||
}
|
||||
WindowsManager::WindowsLocker.Unlock();
|
||||
for (const auto& e : inputEvents)
|
||||
{
|
||||
auto window = e.Target ? e.Target : defaultWindow;
|
||||
if (!window)
|
||||
if (!window || window->IsClosed())
|
||||
continue;
|
||||
switch (e.Type)
|
||||
{
|
||||
@@ -435,12 +436,14 @@ 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;
|
||||
}
|
||||
}
|
||||
WindowsManager::WindowsLocker.Unlock();
|
||||
}
|
||||
WindowsManager::WindowsLocker.Lock();
|
||||
Array<Window*, InlinedAllocation<32>> windows;
|
||||
|
||||
@@ -1013,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);
|
||||
@@ -1135,6 +1135,7 @@ namespace FlaxEditor.Modules
|
||||
Proxy.Add(new FontProxy());
|
||||
Proxy.Add(new ShaderProxy());
|
||||
Proxy.Add(new ShaderSourceProxy());
|
||||
Proxy.Add(new ShaderHeaderProxy());
|
||||
Proxy.Add(new ParticleEmitterProxy());
|
||||
Proxy.Add(new ParticleEmitterFunctionProxy());
|
||||
Proxy.Add(new ParticleSystemProxy());
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -76,6 +76,13 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when Editor will leave the play mode.
|
||||
/// </summary>
|
||||
public virtual void OnPlayEnding()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when Editor leaves the play mode.
|
||||
/// </summary>
|
||||
|
||||
@@ -255,12 +255,17 @@ namespace FlaxEditor.Modules
|
||||
|
||||
// When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff)
|
||||
var originalTransform = instance.LocalTransform;
|
||||
var originalName = instance.Name;
|
||||
if (instance.IsPrefabRoot && instance.HasScene)
|
||||
{
|
||||
instance.LocalTransform = prefab.GetDefaultInstance().Transform;
|
||||
instance.Name = prefab.GetDefaultInstance().Name;
|
||||
}
|
||||
|
||||
// Call backend
|
||||
var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance));
|
||||
instance.LocalTransform = originalTransform;
|
||||
instance.Name = originalName;
|
||||
if (failed)
|
||||
throw new Exception("Failed to apply the prefab. See log to learn more.");
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Actions;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Modules
|
||||
@@ -561,7 +562,8 @@ namespace FlaxEditor.Modules
|
||||
public void CreateParentForSelectedActors()
|
||||
{
|
||||
List<SceneGraphNode> selection = Editor.SceneEditing.Selection;
|
||||
var actors = selection.Where(x => x is ActorNode).Select(x => ((ActorNode)x).Actor);
|
||||
// Get Actors but skip scene node
|
||||
var actors = selection.Where(x => x is ActorNode and not SceneNode).Select(x => ((ActorNode)x).Actor);
|
||||
var actorsCount = actors.Count();
|
||||
if (actorsCount == 0)
|
||||
return;
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace FlaxEditor.Modules
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayBegin()
|
||||
public override void OnPlayBeginning()
|
||||
{
|
||||
Editor.Windows.FlashMainWindow();
|
||||
|
||||
@@ -306,19 +306,21 @@ namespace FlaxEditor.Modules
|
||||
public override void OnPlayEnd()
|
||||
{
|
||||
var gameWin = Editor.Windows.GameWin;
|
||||
|
||||
switch (gameWin.FocusOnPlayOption)
|
||||
if (gameWin != null)
|
||||
{
|
||||
case Options.InterfaceOptions.PlayModeFocus.None: break;
|
||||
case Options.InterfaceOptions.PlayModeFocus.GameWindow: break;
|
||||
case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore:
|
||||
if (_previousWindow != null && !_previousWindow.IsDisposing)
|
||||
switch (gameWin.FocusOnPlayOption)
|
||||
{
|
||||
if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow))
|
||||
break;
|
||||
_previousWindow.Focus();
|
||||
case Options.InterfaceOptions.PlayModeFocus.None: break;
|
||||
case Options.InterfaceOptions.PlayModeFocus.GameWindow: break;
|
||||
case Options.InterfaceOptions.PlayModeFocus.GameWindowThenRestore:
|
||||
if (_previousWindow != null && !_previousWindow.IsDisposing)
|
||||
{
|
||||
if (!Editor.Windows.GameWin.ParentDockPanel.ContainsTab(_previousWindow))
|
||||
break;
|
||||
_previousWindow.Focus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Editor.UI.UncheckPauseButton();
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
{
|
||||
@@ -458,13 +458,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);
|
||||
@@ -628,19 +621,19 @@ namespace FlaxEditor.Modules
|
||||
MenuWindow = MainMenu.AddButton("Window");
|
||||
cm = MenuWindow.ContextMenu;
|
||||
cm.VisibleChanged += OnMenuWindowVisibleChanged;
|
||||
cm.AddButton("Content", Editor.Windows.ContentWin.FocusOrShow);
|
||||
cm.AddButton("Scene", Editor.Windows.SceneWin.FocusOrShow);
|
||||
cm.AddButton("Toolbox", Editor.Windows.ToolboxWin.FocusOrShow);
|
||||
cm.AddButton("Properties", Editor.Windows.PropertiesWin.FocusOrShow);
|
||||
cm.AddButton("Game", Editor.Windows.GameWin.FocusOrShow);
|
||||
cm.AddButton("Editor", Editor.Windows.EditWin.FocusOrShow);
|
||||
cm.AddButton("Debug Log", Editor.Windows.DebugLogWin.FocusOrShow);
|
||||
cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow);
|
||||
cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow);
|
||||
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
||||
cm.AddButton("Content", inputOptions.ContentWindow,Editor.Windows.ContentWin.FocusOrShow);
|
||||
cm.AddButton("Scene", inputOptions.SceneWindow, Editor.Windows.SceneWin.FocusOrShow);
|
||||
cm.AddButton("Toolbox", inputOptions.ToolboxWindow, Editor.Windows.ToolboxWin.FocusOrShow);
|
||||
cm.AddButton("Properties", inputOptions.PropertiesWindow, Editor.Windows.PropertiesWin.FocusOrShow);
|
||||
cm.AddButton("Game", inputOptions.GameWindow, Editor.Windows.GameWin.FocusOrShow);
|
||||
cm.AddButton("Editor", inputOptions.EditorWindow, Editor.Windows.EditWin.FocusOrShow);
|
||||
cm.AddButton("Debug Log", inputOptions.DebugLogWindow, Editor.Windows.DebugLogWin.FocusOrShow);
|
||||
cm.AddButton("Output Log", inputOptions.OutputLogWindow, Editor.Windows.OutputLogWin.FocusOrShow);
|
||||
cm.AddButton("Graphics Quality", inputOptions.GraphicsQualityWindow, Editor.Windows.GraphicsQualityWin.FocusOrShow);
|
||||
cm.AddButton("Game Cooker", inputOptions.GameCookerWindow, Editor.Windows.GameCookerWin.FocusOrShow);
|
||||
cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow);
|
||||
cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch);
|
||||
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
|
||||
cm.AddButton("Content Search", inputOptions.ContentSearchWindow, Editor.ContentFinding.ShowSearch);
|
||||
cm.AddButton("Visual Script Debugger", inputOptions.VisualScriptDebuggerWindow, Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Save window layout", Editor.Windows.SaveLayout);
|
||||
_menuWindowApplyWindowLayout = cm.AddChildMenu("Window layouts");
|
||||
|
||||
@@ -758,6 +758,7 @@ namespace FlaxEditor.Modules
|
||||
var settings = CreateWindowSettings.Default;
|
||||
settings.Title = "Flax Editor";
|
||||
settings.Size = Platform.DesktopSize * 0.75f;
|
||||
settings.MinimumSize = new Float2(200, 150);
|
||||
settings.StartPosition = WindowStartPosition.CenterScreen;
|
||||
settings.ShowAfterFirstPaint = true;
|
||||
#if PLATFORM_WINDOWS
|
||||
@@ -765,8 +766,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;
|
||||
@@ -1223,6 +1226,13 @@ namespace FlaxEditor.Modules
|
||||
Windows[i].OnPlayBegin();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayEnding()
|
||||
{
|
||||
for (int i = 0; i < Windows.Count; i++)
|
||||
Windows[i].OnPlayEnding();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnPlayEnd()
|
||||
{
|
||||
|
||||
@@ -33,6 +33,25 @@ namespace FlaxEditor.Options
|
||||
OpenPrefab,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut availability in play mode.
|
||||
/// </summary>
|
||||
public enum PlayModeShortcutAvailability
|
||||
{
|
||||
/// <summary>
|
||||
/// None of the window shortcuts will be available in play mode.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Only the profiler window shortcut will be available in play mode.
|
||||
/// </summary>
|
||||
ProfilerOnly,
|
||||
/// <summary>
|
||||
/// All window shortcuts will be available in play mode.
|
||||
/// </summary>
|
||||
All,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input editor options data container.
|
||||
/// </summary>
|
||||
@@ -40,6 +59,16 @@ namespace FlaxEditor.Options
|
||||
[HideInEditor]
|
||||
public sealed class InputOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value based on the current settings that indicates wether window shortcuts will be avaliable during play mode.
|
||||
/// </summary>
|
||||
public static bool WindowShortcutsAvaliable => !Editor.IsPlayMode || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.All;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value based on the current settings that indicates wether the profiler window shortcut will be avaliable during play mode.
|
||||
/// </summary>
|
||||
public static bool ProfilerShortcutAvaliable => WindowShortcutsAvaliable || Editor.Instance.Options.Options.Input.PlayModeWindowShortcutAvaliability == PlayModeShortcutAvailability.ProfilerOnly;
|
||||
|
||||
#region Common
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+S")]
|
||||
@@ -110,6 +139,10 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Common"), EditorOrder(240)]
|
||||
public InputBinding ToggleFullscreen = new InputBinding(KeyboardKeys.F11);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+BackQuote")]
|
||||
[EditorDisplay("Common"), EditorOrder(250)]
|
||||
public InputBinding FocusConsoleCommand = new InputBinding(KeyboardKeys.BackQuote, KeyboardKeys.Control);
|
||||
|
||||
#endregion
|
||||
|
||||
#region File
|
||||
@@ -230,9 +263,9 @@ namespace FlaxEditor.Options
|
||||
|
||||
#region Profiler
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha7")]
|
||||
[EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)]
|
||||
public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.None);
|
||||
public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)]
|
||||
@@ -356,24 +389,307 @@ namespace FlaxEditor.Options
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Views
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Alpha4")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2000)]
|
||||
public InputBinding Default = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Alpha3")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2010)]
|
||||
public InputBinding Unlit = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2020)]
|
||||
public InputBinding NoPostFX = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Alpha2")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2030)]
|
||||
public InputBinding Wireframe = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Alpha5")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2040)]
|
||||
public InputBinding LightBuffer = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2050)]
|
||||
public InputBinding ReflectionsBuffer = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2060)]
|
||||
public InputBinding DepthBuffer = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2070)]
|
||||
public InputBinding MotionVectors = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2080)]
|
||||
public InputBinding LightmapUVDensity = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2090)]
|
||||
public InputBinding VertexColors = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Alpha1")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2100)]
|
||||
public InputBinding PhysicsColliders = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2110)]
|
||||
public InputBinding LODPreview = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2120)]
|
||||
public InputBinding MaterialComplexity = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2130)]
|
||||
public InputBinding QuadOverdraw = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2140)]
|
||||
public InputBinding GloablSDF = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2150)]
|
||||
public InputBinding GlobalSurfaceAtlas = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Debug Views"), EditorOrder(2160)]
|
||||
public InputBinding GlobalIllumination = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
#endregion
|
||||
|
||||
#region View Flags
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3000)]
|
||||
public InputBinding AntiAliasing = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3010)]
|
||||
public InputBinding Shadows = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha7")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3020)]
|
||||
public InputBinding EditorSprites = new InputBinding(KeyboardKeys.Alpha7, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3030)]
|
||||
public InputBinding Reflections = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3040)]
|
||||
public InputBinding ScreenSpaceReflections = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3050)]
|
||||
public InputBinding AmbientOcclusion = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha6")]
|
||||
[EditorDisplay("View Flags", "Global Illumination"), EditorOrder(3060)]
|
||||
public InputBinding GlobalIlluminationViewFlag = new InputBinding(KeyboardKeys.Alpha6, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3070)]
|
||||
public InputBinding DirectionalLights = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3080)]
|
||||
public InputBinding PointLights = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3090)]
|
||||
public InputBinding SpotLights = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3100)]
|
||||
public InputBinding SkyLights = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3110)]
|
||||
public InputBinding Sky = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3120)]
|
||||
public InputBinding Fog = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3130)]
|
||||
public InputBinding SpecularLight = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3140)]
|
||||
public InputBinding Decals = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha3")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3150)]
|
||||
public InputBinding CustomPostProcess = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3160)]
|
||||
public InputBinding Bloom = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3170)]
|
||||
public InputBinding ToneMapping = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha2")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3180)]
|
||||
public InputBinding EyeAdaptation = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3190)]
|
||||
public InputBinding CameraArtifacts = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3200)]
|
||||
public InputBinding LensFlares = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3210)]
|
||||
public InputBinding DepthOfField = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3220)]
|
||||
public InputBinding MotionBlur = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3230)]
|
||||
public InputBinding ContactShadows = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha1")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3240)]
|
||||
public InputBinding PhysicsDebug = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha5")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3250)]
|
||||
public InputBinding LightsDebug = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Alpha4")]
|
||||
[EditorDisplay("View Flags"), EditorOrder(3260)]
|
||||
public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interface
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+W")]
|
||||
[EditorDisplay("Interface"), EditorOrder(2000)]
|
||||
[EditorDisplay("Interface"), EditorOrder(3500)]
|
||||
public InputBinding CloseTab = new InputBinding(KeyboardKeys.W, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Tab")]
|
||||
[EditorDisplay("Interface"), EditorOrder(2010)]
|
||||
[EditorDisplay("Interface"), EditorOrder(3510)]
|
||||
public InputBinding NextTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+Ctrl+Tab")]
|
||||
[EditorDisplay("Interface"), EditorOrder(2020)]
|
||||
[EditorDisplay("Interface"), EditorOrder(3520)]
|
||||
public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(SceneNodeDoubleClick.Expand)]
|
||||
[EditorDisplay("Interface"), EditorOrder(2030)]
|
||||
[EditorDisplay("Interface"), EditorOrder(3530)]
|
||||
public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Windows
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating what window shortcuts will be available during play mode.
|
||||
/// </summary>
|
||||
[DefaultValue(PlayModeShortcutAvailability.ProfilerOnly)]
|
||||
[EditorDisplay("Windows", "Avaliability in Play Mode"), EditorOrder(3000)]
|
||||
public PlayModeShortcutAvailability PlayModeWindowShortcutAvaliability { get; set; } = PlayModeShortcutAvailability.ProfilerOnly;
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha5")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3010)]
|
||||
public InputBinding ContentWindow = new InputBinding(KeyboardKeys.Alpha5, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha4")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3020)]
|
||||
public InputBinding SceneWindow = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3030)]
|
||||
public InputBinding ToolboxWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha3")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3040)]
|
||||
public InputBinding PropertiesWindow = new InputBinding(KeyboardKeys.Alpha3, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha2")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3050)]
|
||||
public InputBinding GameWindow = new InputBinding(KeyboardKeys.Alpha2, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Ctrl+Alpha1")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3060)]
|
||||
public InputBinding EditorWindow = new InputBinding(KeyboardKeys.Alpha1, KeyboardKeys.Control);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3070)]
|
||||
public InputBinding DebugLogWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3080)]
|
||||
public InputBinding OutputLogWindow = new InputBinding(KeyboardKeys.C, KeyboardKeys.Control, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(3090)]
|
||||
public InputBinding GraphicsQualityWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(4000)]
|
||||
public InputBinding GameCookerWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(4010)]
|
||||
public InputBinding ContentSearchWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Windows"), EditorOrder(4020)]
|
||||
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Node editors
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+W")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4500)]
|
||||
public InputBinding NodesAlignTop = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+A")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4510)]
|
||||
public InputBinding NodesAlignLeft = new InputBinding(KeyboardKeys.A, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+S")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4520)]
|
||||
public InputBinding NodesAlignBottom = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Shift+D")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4530)]
|
||||
public InputBinding NodesAlignRight = new InputBinding(KeyboardKeys.D, KeyboardKeys.Shift);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Shift+W")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4540)]
|
||||
public InputBinding NodesAlignMiddle = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Alt+Shift+S")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4550)]
|
||||
public InputBinding NodesAlignCenter = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift, KeyboardKeys.Alt);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Q")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4560)]
|
||||
public InputBinding NodesAutoFormat = new InputBinding(KeyboardKeys.Q);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4570)]
|
||||
public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "None")]
|
||||
[EditorDisplay("Node editors"), EditorOrder(4580)]
|
||||
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.None);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace FlaxEditor.SceneGraph
|
||||
return false;
|
||||
}
|
||||
|
||||
BoundingSphere sphere = new BoundingSphere(Transform.Translation, 7.0f);
|
||||
var center = _actor.Transform.Translation;
|
||||
ViewportIconsRenderer.GetBounds(ref center, ref ray.Ray.Position, out var sphere);
|
||||
return CollisionsHelper.RayIntersectsSphere(ref ray.Ray, ref sphere, out distance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
|
||||
var grid = layout.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
gridControl.Height = Button.DefaultHeight;
|
||||
|
||||
@@ -320,7 +320,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
if (noFilter && actor != null)
|
||||
{
|
||||
// Pick the correct id when inside a prefab window.
|
||||
var id = actor.HasPrefabLink && actor.Scene.Scene == null ? actor.PrefabObjectID : actor.ID;
|
||||
var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
|
||||
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref 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();
|
||||
|
||||
@@ -573,11 +573,11 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
"Blend animation poses (with additive mode)" +
|
||||
"\n" +
|
||||
"\nNote: " +
|
||||
"\nOrder of nodes matters, because Additive animation is appplayed on top of curent frame." +
|
||||
"\nThe order of the nodes is important, because additive animation is applied on top of current frame." +
|
||||
"\n" +
|
||||
"\nTip for blender users:" +
|
||||
"\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)" +
|
||||
"\nu need to place it in this order to get correct resoults",
|
||||
"\nInside NLA the the order is bottom (first node in flax) to the top (last node in flax)." +
|
||||
"\nYou need to place animations in this order to get correct results.",
|
||||
Flags = NodeFlags.AnimGraph,
|
||||
Size = new Float2(170, 80),
|
||||
DefaultValues = new object[]
|
||||
|
||||
@@ -534,7 +534,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Tangent Vector",
|
||||
Description = "World space tangent vector",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(160, 40),
|
||||
Size = new Float2(160, 30),
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "Tangent", typeof(Float3), 0),
|
||||
@@ -546,7 +546,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Bitangent Vector",
|
||||
Description = "World space bitangent vector",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(160, 40),
|
||||
Size = new Float2(160, 30),
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "Bitangent", typeof(Float3), 0),
|
||||
@@ -558,7 +558,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Camera Position",
|
||||
Description = "World space camera location",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(160, 40),
|
||||
Size = new Float2(160, 30),
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Float3), 0),
|
||||
@@ -570,7 +570,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Per Instance Random",
|
||||
Description = "Per object instance random value (normalized to range 0-1)",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(200, 40),
|
||||
Size = new Float2(200, 30),
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "", typeof(float), 0),
|
||||
@@ -607,14 +607,14 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Terrain Layer Weight",
|
||||
Description = "Terrain layer weight mask used for blending terrain layers",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(220, 30),
|
||||
Size = new Float2(200, 30),
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
0,
|
||||
},
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.ComboBox(0, 0, 70.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()),
|
||||
NodeElementArchetype.Factory.ComboBox(0, 0, 175.0f, 0, LayersAndTagsSettings.GetCurrentTerrainLayers()),
|
||||
NodeElementArchetype.Factory.Output(0, "", typeof(float), 0),
|
||||
}
|
||||
},
|
||||
|
||||
43
Source/Editor/Surface/NodeAlignmentType.cs
Normal file
43
Source/Editor/Surface/NodeAlignmentType.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
{
|
||||
/// <summary>
|
||||
/// Node Alignment type
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public enum NodeAlignmentType
|
||||
{
|
||||
/// <summary>
|
||||
/// Align nodes vertically to top, matching top-most node
|
||||
/// </summary>
|
||||
Top,
|
||||
|
||||
/// <summary>
|
||||
/// Align nodes vertically to middle, using average of all nodes
|
||||
/// </summary>
|
||||
Middle,
|
||||
|
||||
/// <summary>
|
||||
/// Align nodes vertically to bottom, matching bottom-most node
|
||||
/// </summary>
|
||||
Bottom,
|
||||
|
||||
/// <summary>
|
||||
/// Align nodes horizontally to left, matching left-most node
|
||||
/// </summary>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// Align nodes horizontally to center, using average of all nodes
|
||||
/// </summary>
|
||||
Center,
|
||||
|
||||
/// <summary>
|
||||
/// Align nodes horizontally to right, matching right-most node
|
||||
/// </summary>
|
||||
Right,
|
||||
}
|
||||
}
|
||||
@@ -409,7 +409,7 @@ namespace FlaxEditor.Surface
|
||||
/// <summary>
|
||||
/// Called after adding the control to the surface after paste.
|
||||
/// </summary>
|
||||
/// <param name="idsMapping">The nodes IDs mapping (original node ID to pasted node ID). Can be sued to update internal node's data after paste operation from the original data.</param>
|
||||
/// <param name="idsMapping">The nodes IDs mapping (original node ID to pasted node ID). Can be used to update internal node's data after paste operation from the original data.</param>
|
||||
public virtual void OnPasted(System.Collections.Generic.Dictionary<uint, uint> idsMapping)
|
||||
{
|
||||
}
|
||||
@@ -912,7 +912,7 @@ namespace FlaxEditor.Surface
|
||||
/// <inheritdoc />
|
||||
public override bool OnTestTooltipOverControl(ref Float2 location)
|
||||
{
|
||||
return _headerRect.Contains(ref location) && ShowTooltip;
|
||||
return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1070,7 +1070,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Header
|
||||
var headerColor = style.BackgroundHighlighted;
|
||||
if (_headerRect.Contains(ref _mousePosition))
|
||||
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting)
|
||||
headerColor *= 1.07f;
|
||||
Render2D.FillRectangle(_headerRect, headerColor);
|
||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||
@@ -1078,7 +1078,8 @@ namespace FlaxEditor.Surface
|
||||
// Close button
|
||||
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
|
||||
{
|
||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) ? style.Foreground : style.ForegroundGrey);
|
||||
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting;
|
||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
|
||||
}
|
||||
|
||||
// Footer
|
||||
@@ -1123,8 +1124,9 @@ namespace FlaxEditor.Surface
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
|
||||
// Close
|
||||
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
// Close/ delete
|
||||
bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection;
|
||||
if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
|
||||
{
|
||||
Surface.Delete(this);
|
||||
return true;
|
||||
|
||||
@@ -191,7 +191,16 @@ namespace FlaxEditor.Surface
|
||||
|
||||
private ContextMenuButton _cmCopyButton;
|
||||
private ContextMenuButton _cmDuplicateButton;
|
||||
private ContextMenuChildMenu _cmFormatNodesMenu;
|
||||
private ContextMenuButton _cmFormatNodesConnectionButton;
|
||||
private ContextMenuButton _cmAlignNodesTopButton;
|
||||
private ContextMenuButton _cmAlignNodesMiddleButton;
|
||||
private ContextMenuButton _cmAlignNodesBottomButton;
|
||||
private ContextMenuButton _cmAlignNodesLeftButton;
|
||||
private ContextMenuButton _cmAlignNodesCenterButton;
|
||||
private ContextMenuButton _cmAlignNodesRightButton;
|
||||
private ContextMenuButton _cmDistributeNodesHorizontallyButton;
|
||||
private ContextMenuButton _cmDistributeNodesVerticallyButton;
|
||||
private ContextMenuButton _cmRemoveNodeConnectionsButton;
|
||||
private ContextMenuButton _cmRemoveBoxConnectionsButton;
|
||||
private readonly Float2 ContextMenuOffset = new Float2(5);
|
||||
@@ -399,8 +408,24 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
menu.AddSeparator();
|
||||
|
||||
_cmFormatNodesConnectionButton = menu.AddButton("Format node(s)", () => { FormatGraph(SelectedNodes); });
|
||||
_cmFormatNodesConnectionButton.Enabled = CanEdit && HasNodesSelection;
|
||||
_cmFormatNodesMenu = menu.AddChildMenu("Format node(s)");
|
||||
_cmFormatNodesMenu.Enabled = CanEdit && HasNodesSelection;
|
||||
|
||||
_cmFormatNodesConnectionButton = _cmFormatNodesMenu.ContextMenu.AddButton("Auto format", Editor.Instance.Options.Options.Input.NodesAutoFormat, () => { FormatGraph(SelectedNodes); });
|
||||
|
||||
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||
_cmAlignNodesTopButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align top", Editor.Instance.Options.Options.Input.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); });
|
||||
_cmAlignNodesMiddleButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align middle", Editor.Instance.Options.Options.Input.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); });
|
||||
_cmAlignNodesBottomButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align bottom", Editor.Instance.Options.Options.Input.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); });
|
||||
|
||||
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||
_cmAlignNodesLeftButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align left", Editor.Instance.Options.Options.Input.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); });
|
||||
_cmAlignNodesCenterButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align center", Editor.Instance.Options.Options.Input.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); });
|
||||
_cmAlignNodesRightButton = _cmFormatNodesMenu.ContextMenu.AddButton("Align right", Editor.Instance.Options.Options.Input.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); });
|
||||
|
||||
_cmFormatNodesMenu.ContextMenu.AddSeparator();
|
||||
_cmDistributeNodesHorizontallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute horizontally", Editor.Instance.Options.Options.Input.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); });
|
||||
_cmDistributeNodesVerticallyButton = _cmFormatNodesMenu.ContextMenu.AddButton("Distribute vertically", Editor.Instance.Options.Options.Input.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); });
|
||||
|
||||
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
|
||||
{
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
_rootControl.DrawComments();
|
||||
|
||||
if (IsSelecting)
|
||||
if (IsBoxSelecting)
|
||||
{
|
||||
DrawSelection();
|
||||
}
|
||||
|
||||
@@ -282,5 +282,122 @@ namespace FlaxEditor.Surface
|
||||
|
||||
return maxOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align given nodes on a graph using the given alignment type.
|
||||
/// Ignores any potential overlap.
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of nodes</param>
|
||||
/// <param name="alignmentType">Alignemnt type</param>
|
||||
public void AlignNodes(List<SurfaceNode> nodes, NodeAlignmentType alignmentType)
|
||||
{
|
||||
if(nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
var undoActions = new List<MoveNodesAction>();
|
||||
var boundingBox = GetNodesBounds(nodes);
|
||||
for(int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
var centerY = boundingBox.Center.Y - (nodes[i].Height / 2);
|
||||
var centerX = boundingBox.Center.X - (nodes[i].Width / 2);
|
||||
|
||||
var newLocation = alignmentType switch
|
||||
{
|
||||
NodeAlignmentType.Top => new Float2(nodes[i].Location.X, boundingBox.Top),
|
||||
NodeAlignmentType.Middle => new Float2(nodes[i].Location.X, centerY),
|
||||
NodeAlignmentType.Bottom => new Float2(nodes[i].Location.X, boundingBox.Bottom - nodes[i].Height),
|
||||
|
||||
NodeAlignmentType.Left => new Float2(boundingBox.Left, nodes[i].Location.Y),
|
||||
NodeAlignmentType.Center => new Float2(centerX, nodes[i].Location.Y),
|
||||
NodeAlignmentType.Right => new Float2(boundingBox.Right - nodes[i].Width, nodes[i].Location.Y),
|
||||
|
||||
_ => throw new NotImplementedException($"Unsupported node alignment type: {alignmentType}"),
|
||||
};
|
||||
|
||||
var locationDelta = newLocation - nodes[i].Location;
|
||||
nodes[i].Location = newLocation;
|
||||
|
||||
if(Undo != null)
|
||||
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||
}
|
||||
|
||||
MarkAsEdited(false);
|
||||
Undo?.AddAction(new MultiUndoAction(undoActions, $"Align nodes ({alignmentType})"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distribute the given nodes as equally as possible inside the bounding box, if no fit can be done it will use a default pad of 10 pixels between nodes.
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of nodes</param>
|
||||
/// <param name="vertically">If false will be done horizontally, if true will be done vertically</param>
|
||||
public void DistributeNodes(List<SurfaceNode> nodes, bool vertically)
|
||||
{
|
||||
if(nodes.Count <= 1)
|
||||
return;
|
||||
|
||||
var undoActions = new List<MoveNodesAction>();
|
||||
var boundingBox = GetNodesBounds(nodes);
|
||||
float padding = 10;
|
||||
float totalSize = 0;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
if (vertically)
|
||||
{
|
||||
totalSize += nodes[i].Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalSize += nodes[i].Width;
|
||||
}
|
||||
}
|
||||
|
||||
if(vertically)
|
||||
{
|
||||
nodes.Sort((leftValue, rightValue) => { return leftValue.Y.CompareTo(rightValue.Y); });
|
||||
|
||||
float position = boundingBox.Top;
|
||||
if(totalSize < boundingBox.Height)
|
||||
{
|
||||
padding = (boundingBox.Height - totalSize) / nodes.Count;
|
||||
}
|
||||
|
||||
for(int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
var newLocation = new Float2(nodes[i].X, position);
|
||||
var locationDelta = newLocation - nodes[i].Location;
|
||||
nodes[i].Location = newLocation;
|
||||
|
||||
position += nodes[i].Height + padding;
|
||||
|
||||
if (Undo != null)
|
||||
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.Sort((leftValue, rightValue) => { return leftValue.X.CompareTo(rightValue.X); });
|
||||
|
||||
float position = boundingBox.Left;
|
||||
if(totalSize < boundingBox.Width)
|
||||
{
|
||||
padding = (boundingBox.Width - totalSize) / nodes.Count;
|
||||
}
|
||||
|
||||
for(int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
var newLocation = new Float2(position, nodes[i].Y);
|
||||
var locationDelta = newLocation - nodes[i].Location;
|
||||
nodes[i].Location = newLocation;
|
||||
|
||||
position += nodes[i].Width + padding;
|
||||
|
||||
if (Undo != null)
|
||||
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||
}
|
||||
}
|
||||
|
||||
MarkAsEdited(false);
|
||||
Undo?.AddAction(new MultiUndoAction(undoActions, vertically ? "Distribute nodes vertically" : "Distribute nodes horizontally"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace FlaxEditor.Surface
|
||||
private Float2 _movingNodesDelta;
|
||||
private Float2 _gridRoundingDelta;
|
||||
private HashSet<SurfaceNode> _movingNodes;
|
||||
private HashSet<SurfaceNode> _temporarySelectedNodes;
|
||||
private readonly Stack<InputBracket> _inputBrackets = new Stack<InputBracket>();
|
||||
|
||||
private class InputBracket
|
||||
@@ -130,13 +131,34 @@ namespace FlaxEditor.Surface
|
||||
if (_rootControl.Children[i] is SurfaceControl control)
|
||||
{
|
||||
var select = control.IsSelectionIntersecting(ref selectionRect);
|
||||
if (select != control.IsSelected)
|
||||
|
||||
if (Root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
control.IsSelected = select;
|
||||
selectionChanged = true;
|
||||
if (select == control.IsSelected && _temporarySelectedNodes.Contains(control))
|
||||
{
|
||||
control.IsSelected = !select;
|
||||
selectionChanged = true;
|
||||
}
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
if (select != control.IsSelected && !_temporarySelectedNodes.Contains(control))
|
||||
{
|
||||
control.IsSelected = select;
|
||||
selectionChanged = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (select != control.IsSelected)
|
||||
{
|
||||
control.IsSelected = select;
|
||||
selectionChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionChanged)
|
||||
SelectionChanged?.Invoke();
|
||||
}
|
||||
@@ -369,24 +391,14 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
// Change scale (disable scaling during selecting nodes)
|
||||
if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened)
|
||||
if (IsMouseOver && !_leftMouseDown && !_rightMouseDown && !IsPrimaryMenuOpened)
|
||||
{
|
||||
var nextViewScale = ViewScale + delta * 0.1f;
|
||||
|
||||
if (delta > 0 && !_rightMouseDown)
|
||||
{
|
||||
// Scale towards mouse when zooming in
|
||||
var nextCenterPosition = ViewPosition + location / ViewScale;
|
||||
ViewScale = nextViewScale;
|
||||
ViewPosition = nextCenterPosition - (location / ViewScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scale while keeping center position when zooming out or when dragging view
|
||||
var viewCenter = ViewCenterPosition;
|
||||
ViewScale = nextViewScale;
|
||||
ViewCenterPosition = viewCenter;
|
||||
}
|
||||
// Scale towards/ away from mouse when zooming in/ out
|
||||
var nextCenterPosition = ViewPosition + location / ViewScale;
|
||||
ViewScale = nextViewScale;
|
||||
ViewPosition = nextCenterPosition - (location / ViewScale);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -471,6 +483,19 @@ namespace FlaxEditor.Surface
|
||||
// Cache data
|
||||
_isMovingSelection = false;
|
||||
_mousePos = location;
|
||||
if(_temporarySelectedNodes == null)
|
||||
_temporarySelectedNodes = new HashSet<SurfaceNode>();
|
||||
else
|
||||
_temporarySelectedNodes.Clear();
|
||||
|
||||
for (int i = 0; i < _rootControl.Children.Count; i++)
|
||||
{
|
||||
if (_rootControl.Children[i] is SurfaceNode node && node.IsSelected)
|
||||
{
|
||||
_temporarySelectedNodes.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
_leftMouseDown = true;
|
||||
@@ -498,11 +523,11 @@ namespace FlaxEditor.Surface
|
||||
// Check if user is pressing control
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
// Add to selection
|
||||
if (!controlUnderMouse.IsSelected)
|
||||
{
|
||||
AddToSelection(controlUnderMouse);
|
||||
}
|
||||
AddToSelection(controlUnderMouse);
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
RemoveFromSelection(controlUnderMouse);
|
||||
}
|
||||
// Check if node isn't selected
|
||||
else if (!controlUnderMouse.IsSelected)
|
||||
@@ -512,10 +537,14 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
// Start moving selected nodes
|
||||
StartMouseCapture();
|
||||
_movingSelectionViewPos = _rootControl.Location;
|
||||
_movingNodesDelta = Float2.Zero;
|
||||
OnGetNodesToMove();
|
||||
if (!Root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
StartMouseCapture();
|
||||
_movingSelectionViewPos = _rootControl.Location;
|
||||
_movingNodesDelta = Float2.Zero;
|
||||
OnGetNodesToMove();
|
||||
}
|
||||
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
@@ -527,7 +556,12 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
// Start selecting or commenting
|
||||
StartMouseCapture();
|
||||
ClearSelection();
|
||||
|
||||
if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
@@ -556,6 +590,9 @@ namespace FlaxEditor.Surface
|
||||
// Cache flags and state
|
||||
if (_leftMouseDown && button == MouseButton.Left)
|
||||
{
|
||||
WasBoxSelecting = IsBoxSelecting;
|
||||
WasMovingSelection = _isMovingSelection;
|
||||
|
||||
_leftMouseDown = false;
|
||||
EndMouseCapture();
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
@@ -232,15 +232,25 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is selecting nodes.
|
||||
/// Gets a value indicating whether user is box selecting nodes.
|
||||
/// </summary>
|
||||
public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
|
||||
public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user was previously box selecting nodes.
|
||||
/// </summary>
|
||||
public bool WasBoxSelecting { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is moving selected nodes.
|
||||
/// </summary>
|
||||
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user was previously moving selected nodes.
|
||||
/// </summary>
|
||||
public bool WasMovingSelection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether user is connecting nodes.
|
||||
/// </summary>
|
||||
@@ -405,6 +415,15 @@ namespace FlaxEditor.Surface
|
||||
new InputActionsContainer.Binding(options => options.Paste, Paste),
|
||||
new InputActionsContainer.Binding(options => options.Cut, Cut),
|
||||
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
|
||||
new InputActionsContainer.Binding(options => options.NodesAutoFormat, () => { FormatGraph(SelectedNodes); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignTop, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Top); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignMiddle, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Middle); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignBottom, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Bottom); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignLeft, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Left); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignCenter, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Center); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesAlignRight, () => { AlignNodes(SelectedNodes, NodeAlignmentType.Right); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeHorizontal, () => { DistributeNodes(SelectedNodes, false); }),
|
||||
new InputActionsContainer.Binding(options => options.NodesDistributeVertical, () => { DistributeNodes(SelectedNodes, true); }),
|
||||
});
|
||||
|
||||
Context.ControlSpawned += OnSurfaceControlSpawned;
|
||||
@@ -710,6 +729,18 @@ namespace FlaxEditor.Surface
|
||||
SelectionChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified control from the selection.
|
||||
/// </summary>
|
||||
/// <param name="control">The control.</param>
|
||||
public void RemoveFromSelection(SurfaceControl control)
|
||||
{
|
||||
if (!control.IsSelected)
|
||||
return;
|
||||
control.IsSelected = false;
|
||||
SelectionChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the specified control.
|
||||
/// </summary>
|
||||
|
||||
@@ -20,5 +20,7 @@ namespace FlaxEditor.Utilities
|
||||
#else
|
||||
public const string ShowInExplorer = "Show in explorer";
|
||||
#endif
|
||||
|
||||
public const float UIMargin = 3.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ScreenUtilities.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
|
||||
Delegate<Color32> ScreenUtilities::PickColorDone;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma comment(lib, "Gdi32.lib")
|
||||
|
||||
static HHOOK MouseCallbackHook;
|
||||
|
||||
LRESULT CALLBACK OnScreenUtilsMouseCallback(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
|
||||
{
|
||||
if (nCode >= 0 && wParam == WM_LBUTTONDOWN)
|
||||
{
|
||||
UnhookWindowsHookEx(MouseCallbackHook);
|
||||
|
||||
// Push event with the picked color
|
||||
const Float2 cursorPos = Platform::GetMousePosition();
|
||||
const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos);
|
||||
ScreenUtilities::PickColorDone(colorPicked);
|
||||
return 1;
|
||||
}
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
HDC deviceContext = GetDC(NULL);
|
||||
COLORREF color = GetPixel(deviceContext, (int)pos.X, (int)pos.Y);
|
||||
ReleaseDC(NULL, deviceContext);
|
||||
return Color32(GetRValue(color), GetGValue(color), GetBValue(color), 255);
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
MouseCallbackHook = SetWindowsHookEx(WH_MOUSE_LL, OnScreenUtilsMouseCallback, NULL, NULL);
|
||||
if (MouseCallbackHook == NULL)
|
||||
{
|
||||
LOG(Warning, "Failed to set mouse hook.");
|
||||
LOG(Warning, "Error: {0}", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
#elif PLATFORM_LINUX
|
||||
|
||||
#include "Engine/Platform/Linux/LinuxPlatform.h"
|
||||
#include "Engine/Platform/Linux/IncludeX11.h"
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
X11::XColor color;
|
||||
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
int defaultScreen = X11::XDefaultScreen(display);
|
||||
|
||||
X11::XImage* image;
|
||||
image = X11::XGetImage(display, X11::XRootWindow(display, defaultScreen), (int)pos.X, (int)pos.Y, 1, 1, AllPlanes, XYPixmap);
|
||||
color.pixel = XGetPixel(image, 0, 0);
|
||||
X11::XFree(image);
|
||||
|
||||
X11::XQueryColor(display, X11::XDefaultColormap(display, defaultScreen), &color);
|
||||
|
||||
Color32 outputColor;
|
||||
outputColor.R = color.red / 256;
|
||||
outputColor.G = color.green / 256;
|
||||
outputColor.B = color.blue / 256;
|
||||
outputColor.A = 255;
|
||||
return outputColor;
|
||||
}
|
||||
|
||||
void OnScreenUtilsXEventCallback(void* eventPtr)
|
||||
{
|
||||
X11::XEvent* event = (X11::XEvent*) eventPtr;
|
||||
X11::Display* display = (X11::Display*)LinuxPlatform::GetXDisplay();
|
||||
if (event->type == ButtonPress)
|
||||
{
|
||||
const Float2 cursorPos = Platform::GetMousePosition();
|
||||
const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos);
|
||||
X11::XUngrabPointer(display, CurrentTime);
|
||||
ScreenUtilities::PickColorDone(colorPicked);
|
||||
LinuxPlatform::xEventRecieved.Unbind(OnScreenUtilsXEventCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display));
|
||||
|
||||
X11::Cursor cursor = XCreateFontCursor(display, 130);
|
||||
int grabbedPointer = X11::XGrabPointer(display, rootWindow, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, rootWindow, cursor, CurrentTime);
|
||||
if (grabbedPointer != GrabSuccess)
|
||||
{
|
||||
LOG(Error, "Failed to grab cursor for events.");
|
||||
X11::XFreeCursor(display, cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
X11::XFreeCursor(display, cursor);
|
||||
LinuxPlatform::xEventRecieved.Bind(OnScreenUtilsXEventCallback);
|
||||
}
|
||||
|
||||
#elif PLATFORM_MAC
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
// TODO: implement ScreenUtilities for macOS
|
||||
return { 0, 0, 0, 255 };
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
// This is what C# calls to start the color picking sequence
|
||||
// This should stop mouse clicks from working for one click, and that click is on the selected color
|
||||
// There is a class called NSColorSample that might implement that for you, but maybe not.
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,32 +2,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
|
||||
/// <summary>
|
||||
/// Platform-dependent screen utilities.
|
||||
/// </summary>
|
||||
API_CLASS(Static) class FLAXENGINE_API ScreenUtilities
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(ScreenUtilities);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel color at the specified coordinates.
|
||||
/// </summary>
|
||||
/// <param name="pos">Screen-space coordinate to read.</param>
|
||||
/// <returns>Pixel color at the specified coordinates.</returns>
|
||||
API_FUNCTION() static Color32 GetColorAt(const Float2& pos);
|
||||
|
||||
/// <summary>
|
||||
/// Starts async color picking. Color will be returned through PickColorDone event when the actions ends (user selected the final color with a mouse). When action is active, GetColorAt can be used to read the current value.
|
||||
/// </summary>
|
||||
API_FUNCTION() static void PickColor();
|
||||
|
||||
/// <summary>
|
||||
/// Called when PickColor action is finished.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Color32> PickColorDone;
|
||||
};
|
||||
#include "Engine/Platform/ScreenUtilities.h"
|
||||
|
||||
@@ -402,7 +402,7 @@ namespace FlaxEditor.Utilities
|
||||
/// <summary>
|
||||
/// Creates an Import path ui that show the asset import path and adds a button to show the folder in the file system.
|
||||
/// </summary>
|
||||
/// <param name="parentLayout">The parent layout container.</param>
|
||||
/// <param name="parentLayout">The parent layout element.</param>
|
||||
/// <param name="assetItem">The asset item to get the import path of.</param>
|
||||
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, Content.BinaryAssetItem assetItem)
|
||||
{
|
||||
@@ -413,21 +413,16 @@ namespace FlaxEditor.Utilities
|
||||
/// <summary>
|
||||
/// Creates an Import path ui that show the import path and adds a button to show the folder in the file system.
|
||||
/// </summary>
|
||||
/// <param name="parentLayout">The parent layout container.</param>
|
||||
/// <param name="parentLayout">The parent layout element.</param>
|
||||
/// <param name="path">The import path.</param>
|
||||
/// <param name="useInitialSpacing">Whether to use an initial layout space of 5 for separation.</param>
|
||||
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true)
|
||||
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
if (useInitialSpacing)
|
||||
parentLayout.Space(5);
|
||||
parentLayout.Label("Import Path:").Label.TooltipText = "Source asset path (can be relative or absolute to the project)";
|
||||
var textBox = parentLayout.TextBox().TextBox;
|
||||
textBox.TooltipText = "Path is not editable here.";
|
||||
textBox.TooltipText = "Source asset path. Can be relative or absolute to the project. Path is not editable here.";
|
||||
textBox.IsReadOnly = true;
|
||||
textBox.Text = path;
|
||||
parentLayout.Space(2);
|
||||
var button = parentLayout.Button(Constants.ShowInExplorer).Button;
|
||||
button.Clicked += () => FileSystem.ShowFileExplorer(Path.GetDirectoryName(path));
|
||||
}
|
||||
@@ -1505,7 +1500,6 @@ namespace FlaxEditor.Utilities
|
||||
inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh);
|
||||
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
|
||||
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
|
||||
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
|
||||
#if USE_PROFILER
|
||||
inputActions.Add(options => options.ProfilerStartStop, () =>
|
||||
{
|
||||
@@ -1524,6 +1518,7 @@ namespace FlaxEditor.Utilities
|
||||
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
||||
inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
|
||||
inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
|
||||
inputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand());
|
||||
}
|
||||
|
||||
internal static string ToPathProject(string path)
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
#include "Engine/Level/Actors/SpotLight.h"
|
||||
#include "Engine/Video/VideoPlayer.h"
|
||||
|
||||
#define ICON_RADIUS 7.0f
|
||||
|
||||
enum class IconTypes
|
||||
{
|
||||
PointLight,
|
||||
@@ -66,6 +64,16 @@ public:
|
||||
};
|
||||
|
||||
ViewportIconsRendererService ViewportIconsRendererServiceInstance;
|
||||
float ViewportIconsRenderer::Scale = 1.0f;
|
||||
|
||||
void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds)
|
||||
{
|
||||
constexpr Real minSize = 7.0;
|
||||
constexpr Real maxSize = 30.0;
|
||||
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / 1000.0f);
|
||||
Real radius = minSize + Math::Min<Real>(scale, 1.0f) * (maxSize - minSize);
|
||||
bounds = BoundingSphere(position, radius * Scale);
|
||||
}
|
||||
|
||||
void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor)
|
||||
{
|
||||
@@ -133,7 +141,8 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
|
||||
AssetReference<Texture> texture;
|
||||
for (Actor* icon : icons)
|
||||
{
|
||||
BoundingSphere sphere(icon->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
|
||||
BoundingSphere sphere;
|
||||
ViewportIconsRenderer::GetBounds(icon->GetPosition() - renderContext.View.Origin, renderContext.View.Position, sphere);
|
||||
if (!frustum.Intersects(sphere))
|
||||
continue;
|
||||
IconTypes iconType;
|
||||
@@ -173,7 +182,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene
|
||||
if (draw.Buffer)
|
||||
{
|
||||
// Create world matrix
|
||||
Matrix::Scaling(ICON_RADIUS * 2.0f, m2);
|
||||
Matrix::Scaling((float)sphere.Radius * 2.0f, m2);
|
||||
Matrix::RotationY(PI, world);
|
||||
Matrix::Multiply(m2, world, m1);
|
||||
Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2);
|
||||
@@ -193,14 +202,15 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
||||
auto& view = renderContext.View;
|
||||
const BoundingFrustum frustum = view.Frustum;
|
||||
Matrix m1, m2, world;
|
||||
BoundingSphere sphere(actor->GetPosition() - renderContext.View.Origin, ICON_RADIUS);
|
||||
BoundingSphere sphere;
|
||||
ViewportIconsRenderer::GetBounds(actor->GetPosition() - renderContext.View.Origin, renderContext.View.Position, sphere);
|
||||
IconTypes iconType;
|
||||
AssetReference<Texture> texture;
|
||||
|
||||
if (frustum.Intersects(sphere) && ActorTypeToIconType.TryGet(actor->GetTypeHandle(), iconType))
|
||||
{
|
||||
// Create world matrix
|
||||
Matrix::Scaling(ICON_RADIUS * 2.0f, m2);
|
||||
Matrix::Scaling((float)sphere.Radius * 2.0f, m2);
|
||||
Matrix::RotationY(PI, world);
|
||||
Matrix::Multiply(m2, world, m1);
|
||||
Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2);
|
||||
|
||||
@@ -17,6 +17,19 @@ API_CLASS(Static, Namespace="FlaxEditor") class FLAXENGINE_API ViewportIconsRend
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(ViewportIconsRenderer);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Global scale of the icons.
|
||||
/// </summary>
|
||||
API_FIELD() static float Scale;
|
||||
|
||||
/// <summary>
|
||||
/// Draws the icons for the actors in the given scene (or actor tree).
|
||||
/// </summary>
|
||||
/// <param name="position">The icon position.</param>
|
||||
/// <param name="viewPosition">The viewer position.</param>
|
||||
/// <param name="bounds">The computed bounds for the icon.</param>
|
||||
API_FUNCTION() static void GetBounds(API_PARAM(Ref) const Vector3& position, API_PARAM(Ref) const Vector3& viewPosition, API_PARAM(Out) BoundingSphere& bounds);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the icons for the actors in the given scene (or actor tree).
|
||||
/// </summary>
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace FlaxEditor.Viewport
|
||||
public bool SnapToVertex => ContainsFocus && Editor.Instance.Options.Options.Input.SnapToVertex.Process(Root);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Float2 MouseDelta => _mouseDelta;
|
||||
public Float2 MouseDelta => FlaxEngine.Input.MousePositionDelta;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool UseSnapping => Root?.GetKey(KeyboardKeys.Control) ?? false;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEditor.Viewport.Cameras;
|
||||
@@ -158,18 +159,22 @@ namespace FlaxEditor.Viewport
|
||||
private float _movementSpeed;
|
||||
private float _minMovementSpeed;
|
||||
private float _maxMovementSpeed;
|
||||
#if !PLATFORM_SDL
|
||||
private float _mouseAccelerationScale;
|
||||
private bool _useMouseFiltering;
|
||||
private bool _useMouseAcceleration;
|
||||
#endif
|
||||
|
||||
// Input
|
||||
|
||||
internal bool _disableInputUpdate;
|
||||
private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
|
||||
private int _deltaFilteringStep;
|
||||
private Float2 _startPos;
|
||||
#if !PLATFORM_SDL
|
||||
private Float2 _mouseDeltaLast;
|
||||
private int _deltaFilteringStep;
|
||||
private Float2[] _deltaFilteringBuffer = new Float2[FpsCameraFilteringFrames];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The previous input (from the previous update).
|
||||
@@ -522,10 +527,11 @@ namespace FlaxEditor.Viewport
|
||||
: base(task)
|
||||
{
|
||||
_editor = Editor.Instance;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
_mouseAccelerationScale = 0.1f;
|
||||
_useMouseFiltering = false;
|
||||
_useMouseAcceleration = false;
|
||||
#endif
|
||||
_camera = camera;
|
||||
if (_camera != null)
|
||||
_camera.Viewport = this;
|
||||
@@ -910,7 +916,7 @@ namespace FlaxEditor.Viewport
|
||||
for (int i = 0; i < ViewFlagsValues.Length; i++)
|
||||
{
|
||||
var v = ViewFlagsValues[i];
|
||||
var button = viewFlags.AddButton(v.Name);
|
||||
var button = viewFlags.AddButton(v.Name, v.InputBinding.ToString());
|
||||
button.CloseMenuOnClick = false;
|
||||
button.Tag = v.Mode;
|
||||
}
|
||||
@@ -959,7 +965,7 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
else
|
||||
{
|
||||
var button = debugView.AddButton(v.Name);
|
||||
var button = debugView.AddButton(v.Name, v.InputBinding.ToString());
|
||||
button.CloseMenuOnClick = false;
|
||||
button.Tag = v.Mode;
|
||||
}
|
||||
@@ -1002,19 +1008,79 @@ namespace FlaxEditor.Viewport
|
||||
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
|
||||
}
|
||||
|
||||
// Icons Scale
|
||||
{
|
||||
var icons = ViewWidgetButtonMenu.AddButton("Icons");
|
||||
icons.CloseMenuOnClick = false;
|
||||
var iconsValue = new FloatValueBox(ViewportIconsRenderer.Scale, xLocationForExtras, 2, 70.0f, 0.01f, 100.0f, 0.001f)
|
||||
{
|
||||
Parent = icons
|
||||
};
|
||||
iconsValue.ValueChanged += () => ViewportIconsRenderer.Scale = iconsValue.Value;
|
||||
ViewWidgetButtonMenu.VisibleChanged += control => iconsValue.Value = ViewportIconsRenderer.Scale;
|
||||
}
|
||||
|
||||
#endregion View mode widget
|
||||
}
|
||||
|
||||
// Viewpoints
|
||||
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointBottom, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Bottom").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointFront, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Front").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(CameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
|
||||
// Editor camera
|
||||
InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown);
|
||||
InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1));
|
||||
InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1));
|
||||
InputActions.Add(options => options.ToggleOrthographic, () => OnOrthographicModeToggled(null));
|
||||
// Debug views
|
||||
InputActions.Add(options => options.Default, () => Task.ViewMode = ViewMode.Default);
|
||||
InputActions.Add(options => options.Unlit, () => Task.ViewMode = ViewMode.Unlit);
|
||||
InputActions.Add(options => options.NoPostFX, () => Task.ViewMode = ViewMode.NoPostFx);
|
||||
InputActions.Add(options => options.Wireframe, () => Task.ViewMode = ViewMode.Wireframe);
|
||||
InputActions.Add(options => options.LightBuffer, () => Task.ViewMode = ViewMode.LightBuffer);
|
||||
InputActions.Add(options => options.ReflectionsBuffer, () => Task.ViewMode = ViewMode.Reflections);
|
||||
InputActions.Add(options => options.DepthBuffer, () => Task.ViewMode = ViewMode.Depth);
|
||||
InputActions.Add(options => options.MotionVectors, () => Task.ViewMode = ViewMode.MotionVectors);
|
||||
InputActions.Add(options => options.LightmapUVDensity, () => Task.ViewMode = ViewMode.LightmapUVsDensity);
|
||||
InputActions.Add(options => options.VertexColors, () => Task.ViewMode = ViewMode.VertexColors);
|
||||
InputActions.Add(options => options.PhysicsColliders, () => Task.ViewMode = ViewMode.PhysicsColliders);
|
||||
InputActions.Add(options => options.LODPreview, () => Task.ViewMode = ViewMode.LODPreview);
|
||||
InputActions.Add(options => options.MaterialComplexity, () => Task.ViewMode = ViewMode.MaterialComplexity);
|
||||
InputActions.Add(options => options.QuadOverdraw, () => Task.ViewMode = ViewMode.QuadOverdraw);
|
||||
InputActions.Add(options => options.GloablSDF, () => Task.ViewMode = ViewMode.GlobalSDF);
|
||||
InputActions.Add(options => options.GlobalSurfaceAtlas, () => Task.ViewMode = ViewMode.GlobalSurfaceAtlas);
|
||||
InputActions.Add(options => options.GlobalIllumination, () => Task.ViewMode = ViewMode.GlobalIllumination);
|
||||
// View flags
|
||||
InputActions.Add(options => options.AntiAliasing, () => Task.ViewFlags ^= ViewFlags.AntiAliasing);
|
||||
InputActions.Add(options => options.Shadows, () => Task.ViewFlags ^= ViewFlags.Shadows);
|
||||
InputActions.Add(options => options.EditorSprites, () => Task.ViewFlags ^= ViewFlags.EditorSprites);
|
||||
InputActions.Add(options => options.Reflections, () => Task.ViewFlags ^= ViewFlags.Reflections);
|
||||
InputActions.Add(options => options.ScreenSpaceReflections, () => Task.ViewFlags ^= ViewFlags.SSR);
|
||||
InputActions.Add(options => options.AmbientOcclusion, () => Task.ViewFlags ^= ViewFlags.AO);
|
||||
InputActions.Add(options => options.GlobalIllumination, () => Task.ViewFlags ^= ViewFlags.GI);
|
||||
InputActions.Add(options => options.DirectionalLights, () => Task.ViewFlags ^= ViewFlags.DirectionalLights);
|
||||
InputActions.Add(options => options.PointLights, () => Task.ViewFlags ^= ViewFlags.PointLights);
|
||||
InputActions.Add(options => options.SpotLights, () => Task.ViewFlags ^= ViewFlags.SpotLights);
|
||||
InputActions.Add(options => options.SkyLights, () => Task.ViewFlags ^= ViewFlags.SkyLights);
|
||||
InputActions.Add(options => options.Sky, () => Task.ViewFlags ^= ViewFlags.Sky);
|
||||
InputActions.Add(options => options.Fog, () => Task.ViewFlags ^= ViewFlags.Fog);
|
||||
InputActions.Add(options => options.SpecularLight, () => Task.ViewFlags ^= ViewFlags.SpecularLight);
|
||||
InputActions.Add(options => options.Decals, () => Task.ViewFlags ^= ViewFlags.Decals);
|
||||
InputActions.Add(options => options.CustomPostProcess, () => Task.ViewFlags ^= ViewFlags.CustomPostProcess);
|
||||
InputActions.Add(options => options.Bloom, () => Task.ViewFlags ^= ViewFlags.Bloom);
|
||||
InputActions.Add(options => options.ToneMapping, () => Task.ViewFlags ^= ViewFlags.ToneMapping);
|
||||
InputActions.Add(options => options.EyeAdaptation, () => Task.ViewFlags ^= ViewFlags.EyeAdaptation);
|
||||
InputActions.Add(options => options.CameraArtifacts, () => Task.ViewFlags ^= ViewFlags.CameraArtifacts);
|
||||
InputActions.Add(options => options.LensFlares, () => Task.ViewFlags ^= ViewFlags.LensFlares);
|
||||
InputActions.Add(options => options.DepthOfField, () => Task.ViewFlags ^= ViewFlags.DepthOfField);
|
||||
InputActions.Add(options => options.MotionBlur, () => Task.ViewFlags ^= ViewFlags.MotionBlur);
|
||||
InputActions.Add(options => options.ContactShadows, () => Task.ViewFlags ^= ViewFlags.ContactShadows);
|
||||
InputActions.Add(options => options.PhysicsDebug, () => Task.ViewFlags ^= ViewFlags.PhysicsDebug);
|
||||
InputActions.Add(options => options.LightsDebug, () => Task.ViewFlags ^= ViewFlags.LightsDebug);
|
||||
InputActions.Add(options => options.DebugDraw, () => Task.ViewFlags ^= ViewFlags.DebugDraw);
|
||||
|
||||
// Link for task event
|
||||
task.Begin += OnRenderBegin;
|
||||
@@ -1460,7 +1526,9 @@ namespace FlaxEditor.Viewport
|
||||
// Hide cursor and start tracking mouse movement
|
||||
win.StartTrackingMouse(false);
|
||||
win.Cursor = CursorType.Hidden;
|
||||
win.MouseMoveRelative += OnMouseMoveRelative;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Center mouse position if it's too close to the edge
|
||||
var size = Size;
|
||||
var center = Float2.Round(size * 0.5f);
|
||||
@@ -1469,6 +1537,7 @@ namespace FlaxEditor.Viewport
|
||||
_viewMousePos = center;
|
||||
win.MousePosition = PointToWindow(_viewMousePos);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1480,6 +1549,7 @@ namespace FlaxEditor.Viewport
|
||||
// Restore cursor and stop tracking mouse movement
|
||||
win.Cursor = CursorType.Default;
|
||||
win.EndTrackingMouse();
|
||||
win.MouseMoveRelative -= OnMouseMoveRelative;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1561,18 +1631,15 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
// Get parent window
|
||||
var win = (WindowRootControl)Root;
|
||||
|
||||
// Get current mouse position in the view
|
||||
if (win.IsFocused)
|
||||
{
|
||||
// When the window is not focused, the position in window does not return sane values
|
||||
Float2 pos = PointFromWindow(win.MousePosition);
|
||||
if (!float.IsInfinity(pos.LengthSquared))
|
||||
_viewMousePos = pos;
|
||||
// Get current mouse position in the view
|
||||
_viewMousePos = PointFromWindow(win.MousePosition);
|
||||
}
|
||||
|
||||
// Update input
|
||||
var window = win.Window;
|
||||
var canUseInput = window != null && window.IsFocused && window.IsForegroundWindow;
|
||||
var canUseInput = window != null && window.IsFocused && window.IsForegroundWindow && !WindowDragHelper.IsDragActive;
|
||||
{
|
||||
// Get input buttons and keys (skip if viewport has no focus or mouse is over a child control)
|
||||
var isViewportControllingMouse = canUseInput && IsControllingMouse;
|
||||
@@ -1584,9 +1651,17 @@ namespace FlaxEditor.Viewport
|
||||
else
|
||||
EndMouseCapture();
|
||||
}
|
||||
bool useMouse = IsControllingMouse || (Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height));
|
||||
|
||||
_prevInput = _input;
|
||||
#if PLATFORM_SDL
|
||||
bool useMouse = IsControllingMouse || ContainsPoint(ref _viewMousePos) || _prevInput.IsControllingMouse;
|
||||
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
|
||||
if (_prevInput.IsControllingMouse)
|
||||
hit = null;
|
||||
#else
|
||||
bool useMouse = IsControllingMouse || ContainsPoint(ref _viewMousePos);
|
||||
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
|
||||
#endif
|
||||
if (canUseInput && ContainsFocus && hit == null)
|
||||
_input.Gather(win.Window, useMouse, ref _prevInput);
|
||||
else
|
||||
@@ -1699,6 +1774,10 @@ namespace FlaxEditor.Viewport
|
||||
if (_input.IsControlDown)
|
||||
moveDelta *= 0.3f;
|
||||
|
||||
#if PLATFORM_SDL
|
||||
var mouseDelta = _mouseDelta;
|
||||
_mouseDelta = Float2.Zero;
|
||||
#else
|
||||
// Calculate smooth mouse delta not dependant on viewport size
|
||||
var offset = _viewMousePos - _startPos;
|
||||
if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel && !_isVirtualMouseRightDown)
|
||||
@@ -1740,6 +1819,7 @@ namespace FlaxEditor.Viewport
|
||||
mouseDelta += _mouseDeltaLast * _mouseAccelerationScale;
|
||||
_mouseDeltaLast = currentDelta;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update
|
||||
moveDelta *= dt * (60.0f * 4.0f);
|
||||
@@ -1748,12 +1828,14 @@ namespace FlaxEditor.Viewport
|
||||
mouseDelta *= new Float2(1, -1);
|
||||
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Move mouse back to the root position
|
||||
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown || _isVirtualMouseRightDown))
|
||||
{
|
||||
var center = PointToWindow(_startPos);
|
||||
win.MousePosition = center;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Change Ortho size on mouse scroll
|
||||
if (_isOrtho && !rmbWheel)
|
||||
@@ -1765,6 +1847,8 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PLATFORM_SDL
|
||||
#else
|
||||
if (_input.IsMouseLeftDown || _input.IsMouseRightDown || _isVirtualMouseRightDown)
|
||||
{
|
||||
// Calculate smooth mouse delta not dependant on viewport size
|
||||
@@ -1779,6 +1863,7 @@ namespace FlaxEditor.Viewport
|
||||
_mouseDelta = Float2.Zero;
|
||||
}
|
||||
_mouseDeltaLast = Float2.Zero;
|
||||
#endif
|
||||
|
||||
if (ContainsFocus)
|
||||
{
|
||||
@@ -1828,6 +1913,12 @@ namespace FlaxEditor.Viewport
|
||||
_input.MouseWheelDelta = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnMouseMoveRelative(ref Float2 mouseMotion)
|
||||
{
|
||||
_mouseDelta += mouseMotion;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
@@ -1893,7 +1984,8 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
if (_isControllingMouse)
|
||||
{
|
||||
OnControlMouseEnd(RootWindow.Window);
|
||||
if (RootWindow?.Window != null)
|
||||
OnControlMouseEnd(RootWindow.Window);
|
||||
_isControllingMouse = false;
|
||||
_isVirtualMouseRightDown = false;
|
||||
}
|
||||
@@ -1933,8 +2025,17 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly ViewMode Mode;
|
||||
public readonly InputBinding InputBinding;
|
||||
public readonly ViewModeOptions[] Options;
|
||||
|
||||
public ViewModeOptions(ViewMode mode, string name, InputBinding inputBinding)
|
||||
{
|
||||
Mode = mode;
|
||||
Name = name;
|
||||
InputBinding = inputBinding;
|
||||
Options = null;
|
||||
}
|
||||
|
||||
public ViewModeOptions(ViewMode mode, string name)
|
||||
{
|
||||
Mode = mode;
|
||||
@@ -1952,13 +2053,13 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private static readonly ViewModeOptions[] ViewModeValues =
|
||||
{
|
||||
new ViewModeOptions(ViewMode.Default, "Default"),
|
||||
new ViewModeOptions(ViewMode.Unlit, "Unlit"),
|
||||
new ViewModeOptions(ViewMode.NoPostFx, "No PostFx"),
|
||||
new ViewModeOptions(ViewMode.Wireframe, "Wireframe"),
|
||||
new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer"),
|
||||
new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer"),
|
||||
new ViewModeOptions(ViewMode.Depth, "Depth Buffer"),
|
||||
new ViewModeOptions(ViewMode.Default, "Default", Editor.Instance.Options.Options.Input.Default),
|
||||
new ViewModeOptions(ViewMode.Unlit, "Unlit", Editor.Instance.Options.Options.Input.Unlit),
|
||||
new ViewModeOptions(ViewMode.NoPostFx, "No PostFx", Editor.Instance.Options.Options.Input.NoPostFX),
|
||||
new ViewModeOptions(ViewMode.Wireframe, "Wireframe", Editor.Instance.Options.Options.Input.Wireframe),
|
||||
new ViewModeOptions(ViewMode.LightBuffer, "Light Buffer", Editor.Instance.Options.Options.Input.LightBuffer),
|
||||
new ViewModeOptions(ViewMode.Reflections, "Reflections Buffer", Editor.Instance.Options.Options.Input.ReflectionsBuffer),
|
||||
new ViewModeOptions(ViewMode.Depth, "Depth Buffer", Editor.Instance.Options.Options.Input.DepthBuffer),
|
||||
new ViewModeOptions("GBuffer", new[]
|
||||
{
|
||||
new ViewModeOptions(ViewMode.Diffuse, "Diffuse"),
|
||||
@@ -1972,16 +2073,16 @@ namespace FlaxEditor.Viewport
|
||||
new ViewModeOptions(ViewMode.Normals, "Normals"),
|
||||
new ViewModeOptions(ViewMode.AmbientOcclusion, "Ambient Occlusion"),
|
||||
}),
|
||||
new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors"),
|
||||
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density"),
|
||||
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"),
|
||||
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"),
|
||||
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"),
|
||||
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
|
||||
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"),
|
||||
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"),
|
||||
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas"),
|
||||
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"),
|
||||
new ViewModeOptions(ViewMode.MotionVectors, "Motion Vectors", Editor.Instance.Options.Options.Input.MotionVectors),
|
||||
new ViewModeOptions(ViewMode.LightmapUVsDensity, "Lightmap UVs Density", Editor.Instance.Options.Options.Input.LightmapUVDensity),
|
||||
new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors", Editor.Instance.Options.Options.Input.VertexColors),
|
||||
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders", Editor.Instance.Options.Options.Input.PhysicsColliders),
|
||||
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview", Editor.Instance.Options.Options.Input.LODPreview),
|
||||
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity", Editor.Instance.Options.Options.Input.MaterialComplexity),
|
||||
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw", Editor.Instance.Options.Options.Input.QuadOverdraw),
|
||||
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF", Editor.Instance.Options.Options.Input.GloablSDF),
|
||||
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas", Editor.Instance.Options.Options.Input.GlobalSurfaceAtlas),
|
||||
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIllumination),
|
||||
};
|
||||
|
||||
private void WidgetViewModeShowHideClicked(ContextMenuButton button)
|
||||
@@ -2014,43 +2115,45 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
public readonly ViewFlags Mode;
|
||||
public readonly string Name;
|
||||
public readonly InputBinding InputBinding;
|
||||
|
||||
public ViewFlagOptions(ViewFlags mode, string name)
|
||||
public ViewFlagOptions(ViewFlags mode, string name, InputBinding inputBinding)
|
||||
{
|
||||
Mode = mode;
|
||||
Name = name;
|
||||
InputBinding = inputBinding;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ViewFlagOptions[] ViewFlagsValues =
|
||||
{
|
||||
new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing"),
|
||||
new ViewFlagOptions(ViewFlags.Shadows, "Shadows"),
|
||||
new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites"),
|
||||
new ViewFlagOptions(ViewFlags.Reflections, "Reflections"),
|
||||
new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections"),
|
||||
new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion"),
|
||||
new ViewFlagOptions(ViewFlags.GI, "Global Illumination"),
|
||||
new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights"),
|
||||
new ViewFlagOptions(ViewFlags.PointLights, "Point Lights"),
|
||||
new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights"),
|
||||
new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights"),
|
||||
new ViewFlagOptions(ViewFlags.Sky, "Sky"),
|
||||
new ViewFlagOptions(ViewFlags.Fog, "Fog"),
|
||||
new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light"),
|
||||
new ViewFlagOptions(ViewFlags.Decals, "Decals"),
|
||||
new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process"),
|
||||
new ViewFlagOptions(ViewFlags.Bloom, "Bloom"),
|
||||
new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping"),
|
||||
new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation"),
|
||||
new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts"),
|
||||
new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares"),
|
||||
new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field"),
|
||||
new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur"),
|
||||
new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows"),
|
||||
new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug"),
|
||||
new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug"),
|
||||
new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw"),
|
||||
new ViewFlagOptions(ViewFlags.AntiAliasing, "Anti Aliasing", Editor.Instance.Options.Options.Input.AntiAliasing),
|
||||
new ViewFlagOptions(ViewFlags.Shadows, "Shadows", Editor.Instance.Options.Options.Input.Shadows),
|
||||
new ViewFlagOptions(ViewFlags.EditorSprites, "Editor Sprites", Editor.Instance.Options.Options.Input.EditorSprites),
|
||||
new ViewFlagOptions(ViewFlags.Reflections, "Reflections", Editor.Instance.Options.Options.Input.Reflections),
|
||||
new ViewFlagOptions(ViewFlags.SSR, "Screen Space Reflections", Editor.Instance.Options.Options.Input.ScreenSpaceReflections),
|
||||
new ViewFlagOptions(ViewFlags.AO, "Ambient Occlusion", Editor.Instance.Options.Options.Input.AmbientOcclusion),
|
||||
new ViewFlagOptions(ViewFlags.GI, "Global Illumination", Editor.Instance.Options.Options.Input.GlobalIlluminationViewFlag),
|
||||
new ViewFlagOptions(ViewFlags.DirectionalLights, "Directional Lights", Editor.Instance.Options.Options.Input.DirectionalLights),
|
||||
new ViewFlagOptions(ViewFlags.PointLights, "Point Lights", Editor.Instance.Options.Options.Input.PointLights),
|
||||
new ViewFlagOptions(ViewFlags.SpotLights, "Spot Lights", Editor.Instance.Options.Options.Input.SpotLights),
|
||||
new ViewFlagOptions(ViewFlags.SkyLights, "Sky Lights", Editor.Instance.Options.Options.Input.SkyLights),
|
||||
new ViewFlagOptions(ViewFlags.Sky, "Sky", Editor.Instance.Options.Options.Input.Sky),
|
||||
new ViewFlagOptions(ViewFlags.Fog, "Fog", Editor.Instance.Options.Options.Input.Fog),
|
||||
new ViewFlagOptions(ViewFlags.SpecularLight, "Specular Light", Editor.Instance.Options.Options.Input.SpecularLight),
|
||||
new ViewFlagOptions(ViewFlags.Decals, "Decals", Editor.Instance.Options.Options.Input.Decals),
|
||||
new ViewFlagOptions(ViewFlags.CustomPostProcess, "Custom Post Process", Editor.Instance.Options.Options.Input.CustomPostProcess),
|
||||
new ViewFlagOptions(ViewFlags.Bloom, "Bloom", Editor.Instance.Options.Options.Input.Bloom),
|
||||
new ViewFlagOptions(ViewFlags.ToneMapping, "Tone Mapping", Editor.Instance.Options.Options.Input.ToneMapping),
|
||||
new ViewFlagOptions(ViewFlags.EyeAdaptation, "Eye Adaptation", Editor.Instance.Options.Options.Input.EyeAdaptation),
|
||||
new ViewFlagOptions(ViewFlags.CameraArtifacts, "Camera Artifacts", Editor.Instance.Options.Options.Input.CameraArtifacts),
|
||||
new ViewFlagOptions(ViewFlags.LensFlares, "Lens Flares", Editor.Instance.Options.Options.Input.LensFlares),
|
||||
new ViewFlagOptions(ViewFlags.DepthOfField, "Depth of Field", Editor.Instance.Options.Options.Input.DepthOfField),
|
||||
new ViewFlagOptions(ViewFlags.MotionBlur, "Motion Blur", Editor.Instance.Options.Options.Input.MotionBlur),
|
||||
new ViewFlagOptions(ViewFlags.ContactShadows, "Contact Shadows", Editor.Instance.Options.Options.Input.ContactShadows),
|
||||
new ViewFlagOptions(ViewFlags.PhysicsDebug, "Physics Debug", Editor.Instance.Options.Options.Input.PhysicsDebug),
|
||||
new ViewFlagOptions(ViewFlags.LightsDebug, "Lights Debug", Editor.Instance.Options.Options.Input.LightsDebug),
|
||||
new ViewFlagOptions(ViewFlags.DebugDraw, "Debug Draw", Editor.Instance.Options.Options.Input.DebugDraw),
|
||||
};
|
||||
|
||||
private void WidgetViewFlagsShowHide(Control cm)
|
||||
|
||||
@@ -611,16 +611,25 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
// Don't allow rubber band selection when gizmo is controlling mouse, vertex painting mode, or cloth painting is enabled
|
||||
bool canStart = !(IsControllingMouse || IsRightMouseButtonDown || IsAltKeyDown) &&
|
||||
Gizmos?.Active is TransformGizmo && !Gizmos.Active.IsControllingMouse;
|
||||
Gizmos?.Active is TransformGizmo;
|
||||
_rubberBandSelector.TryCreateRubberBand(canStart, _viewMousePos);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnControlMouseBegin(Window win)
|
||||
{
|
||||
_rubberBandSelector.ReleaseRubberBandSelection();
|
||||
|
||||
base.OnControlMouseBegin(win);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnLeftMouseButtonDown()
|
||||
{
|
||||
base.OnLeftMouseButtonDown();
|
||||
|
||||
_rubberBandSelector.TryStartingRubberBandSelection();
|
||||
if (!IsAltKeyDown)
|
||||
_rubberBandSelector.TryStartingRubberBandSelection();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
UseTimeScale = false,
|
||||
UpdateWhenOffscreen = true,
|
||||
BoundsScale = 100.0f,
|
||||
BoundsScale = 1.0f,
|
||||
UpdateMode = AnimatedModel.AnimationUpdateMode.Manual,
|
||||
};
|
||||
Task.AddCustomActor(_previewModel);
|
||||
|
||||
@@ -231,7 +231,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
group.Object(importSettingsValues);
|
||||
|
||||
// Creates the import path UI
|
||||
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
|
||||
group = layout.Group("Import Path");
|
||||
Utilities.Utils.CreateImportPathUI(group, proxy.Window.Item as BinaryAssetItem);
|
||||
|
||||
layout.Space(5);
|
||||
var reimportButton = layout.Button("Reimport");
|
||||
|
||||
@@ -6,6 +6,7 @@ using FlaxEditor.Content.Import;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -76,7 +77,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var window = ((PropertiesProxy)Values[0])._window;
|
||||
var proxy = ((PropertiesProxy)Values[0]);
|
||||
var window = proxy._window;
|
||||
if (window == null)
|
||||
{
|
||||
layout.Label("Loading...", TextAlignment.Center);
|
||||
@@ -101,7 +103,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.Initialize(layout);
|
||||
|
||||
// Creates the import path UI
|
||||
Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem);
|
||||
var pathGroup = layout.Group("Import Path");
|
||||
Utilities.Utils.CreateImportPathUI(pathGroup, window.Item as BinaryAssetItem);
|
||||
|
||||
layout.Space(5);
|
||||
var reimportButton = layout.Button("Reimport");
|
||||
|
||||
@@ -635,5 +635,11 @@ namespace FlaxEditor.Windows.Assets
|
||||
public void Select(List<SceneGraphNode> nodes)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<SceneGraphNode> Selection => new List<SceneGraphNode>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool LockSelection { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private class CookData : CreateFileEntry
|
||||
{
|
||||
public override bool CanBeCreated => true;
|
||||
|
||||
public PropertiesProxy Proxy;
|
||||
public CollisionDataType Type;
|
||||
public ModelBase Model;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user