3 Commits

Author SHA1 Message Date
824ff7050e Fix managed wrapper function parameter handling for BytesContainer
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-12-23 01:41:01 +02:00
042843fe42 Fix clang bindings code generation for non-const ref parameters
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-12-20 23:04:08 +02:00
8631b389c1 asdf 2025-12-20 23:02:42 +02:00
708 changed files with 7745 additions and 182106 deletions

View File

@@ -16,8 +16,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update 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 -y --fix-missing 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 - name: Setup Vulkan
uses: ./.github/actions/vulkan uses: ./.github/actions/vulkan
- name: Setup .NET - name: Setup .NET
@@ -45,7 +44,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev libwayland-dev sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev
- name: Setup Vulkan - name: Setup Vulkan
uses: ./.github/actions/vulkan uses: ./.github/actions/vulkan
- name: Setup .NET - name: Setup .NET

View File

@@ -87,8 +87,7 @@ jobs:
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update 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 -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Setup Vulkan - name: Setup Vulkan
uses: ./.github/actions/vulkan uses: ./.github/actions/vulkan
- name: Setup .NET - name: Setup .NET
@@ -119,8 +118,7 @@ jobs:
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update 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 -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Setup Vulkan - name: Setup Vulkan
uses: ./.github/actions/vulkan uses: ./.github/actions/vulkan
- name: Setup .NET - name: Setup .NET

View File

@@ -28,8 +28,7 @@ jobs:
git lfs pull git lfs pull
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update 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 -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
- name: Build - name: Build
run: | run: |
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8 ./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8

BIN
Content/Editor/Camera/M_Camera.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/DefaultFontMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Gizmo/Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialWire.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Highlight Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Icons/IconsMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@@ -4,8 +4,8 @@
#define MAX_LOCAL_LIGHTS 4 #define MAX_LOCAL_LIGHTS 4
@1// Forward Shading: Includes @1// Forward Shading: Includes
#include "./Flax/LightingCommon.hlsl" #include "./Flax/LightingCommon.hlsl"
#include "./Flax/ReflectionsCommon.hlsl"
#if USE_REFLECTIONS #if USE_REFLECTIONS
#include "./Flax/ReflectionsCommon.hlsl"
#define MATERIAL_REFLECTIONS_SSR 1 #define MATERIAL_REFLECTIONS_SSR 1
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR #if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
#include "./Flax/SSR.hlsl" #include "./Flax/SSR.hlsl"
@@ -14,13 +14,11 @@
#include "./Flax/Lighting.hlsl" #include "./Flax/Lighting.hlsl"
#include "./Flax/ShadowsSampling.hlsl" #include "./Flax/ShadowsSampling.hlsl"
#include "./Flax/ExponentialHeightFog.hlsl" #include "./Flax/ExponentialHeightFog.hlsl"
#include "./Flax/VolumetricFog.hlsl"
@2// Forward Shading: Constants @2// Forward Shading: Constants
LightData DirectionalLight; LightData DirectionalLight;
LightData SkyLight; LightData SkyLight;
EnvProbeData EnvironmentProbe; ProbeData EnvironmentProbe;
ExponentialHeightFogData ExponentialHeightFog; ExponentialHeightFogData ExponentialHeightFog;
VolumetricFogData VolumetricFog;
float3 Dummy2; float3 Dummy2;
uint LocalLightsCount; uint LocalLightsCount;
LightData LocalLights[MAX_LOCAL_LIGHTS]; LightData LocalLights[MAX_LOCAL_LIGHTS];
@@ -30,14 +28,12 @@ TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__); Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__); Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__); Texture3D VolumetricFogTexture : register(t__SRV__);
Texture2D PreIntegratedGF : register(t__SRV__);
@4// Forward Shading: Utilities @4// Forward Shading: Utilities
// Public accessors for lighting data, use them as data binding might change but those methods will remain. // Public accessors for lighting data, use them as data binding might change but those methods will remain.
LightData GetDirectionalLight() { return DirectionalLight; } LightData GetDirectionalLight() { return DirectionalLight; }
LightData GetSkyLight() { return SkyLight; } LightData GetSkyLight() { return SkyLight; }
EnvProbeData GetEnvironmentProbe() { return EnvironmentProbe; } ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; } ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
VolumetricFogData GetVolumetricFog() { return VolumetricFog; }
uint GetLocalLightsCount() { return LocalLightsCount; } uint GetLocalLightsCount() { return LocalLightsCount; }
LightData GetLocalLight(uint i) { return LocalLights[i]; } LightData GetLocalLight(uint i) { return LocalLights[i]; }
@5// Forward Shading: Shaders @5// Forward Shading: Shaders
@@ -112,8 +108,7 @@ void PS_Forward(
// Calculate reflections // Calculate reflections
#if USE_REFLECTIONS #if USE_REFLECTIONS
float4 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness); float3 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb;
reflections.rgb *= reflections.a;
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR #if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
// Screen Space Reflections // Screen Space Reflections
@@ -121,7 +116,7 @@ void PS_Forward(
Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR; Texture2D sceneColorTexture = MATERIAL_REFLECTIONS_SSR_COLOR;
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw; float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float stepSize = ScreenSize.z; // 1 / screenWidth float stepSize = ScreenSize.z; // 1 / screenWidth
float maxSamples = 50; float maxSamples = 48;
float worldAntiSelfOcclusionBias = 0.1f; float worldAntiSelfOcclusionBias = 0.1f;
float brdfBias = 0.82f; float brdfBias = 0.82f;
float drawDistance = 5000.0f; float drawDistance = 5000.0f;
@@ -129,7 +124,7 @@ void PS_Forward(
if (hit.z > 0) if (hit.z > 0)
{ {
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb; float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections.rgb = lerp(reflections.rgb, screenColor, hit.z); reflections = lerp(reflections, screenColor, hit.z);
} }
// Fallback to software tracing if possible // Fallback to software tracing if possible
@@ -141,17 +136,17 @@ void PS_Forward(
if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas)) if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas))
{ {
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb; float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections.rgb = lerp(surfaceAtlas, float4(screenColor, 1), hit.z); reflections = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
} }
} }
#endif #endif
#endif #endif
light.rgb += reflections.rgb * GetReflectionSpecularLighting(PreIntegratedGF, ViewPos, gBuffer); light.rgb += reflections * GetReflectionSpecularLighting(ViewPos, gBuffer) * light.a;
#endif #endif
// Add lighting // Add lighting (apply ambient occlusion)
output.rgb += light.rgb; output.rgb += light.rgb * gBuffer.AO;
#endif #endif
@@ -163,13 +158,17 @@ void PS_Forward(
#else #else
float fogSceneDistance = gBuffer.ViewPos.z; float fogSceneDistance = gBuffer.ViewPos.z;
#endif #endif
float fogSkipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0); float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance);
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, fogSkipDistance, fogSceneDistance);
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0) if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
{ {
// Sample volumetric fog and mix it in // Sample volumetric fog and mix it in
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw; float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, VolumetricFog, materialInput.WorldPosition - ViewPos, screenUV, TemporalAAJitter); float3 viewVector = materialInput.WorldPosition - ViewPos;
float sceneDepth = length(viewVector);
float depthSlice = sceneDepth / ExponentialHeightFog.VolumetricFogMaxDistance;
float3 volumeUV = float3(screenUV, depthSlice);
float4 volumetricFog = VolumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0);
fog = CombineVolumetricFog(fog, volumetricFog); fog = CombineVolumetricFog(fog, volumetricFog);
} }

View File

@@ -38,7 +38,6 @@ struct VertexOutput
#endif #endif
float4 ClipExtents : TEXCOORD3; float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4; float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9; float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif #endif
@@ -56,7 +55,6 @@ struct PixelInput
#endif #endif
float4 ClipExtents : TEXCOORD3; float4 ClipExtents : TEXCOORD3;
float2 ClipOrigin : TEXCOORD4; float2 ClipOrigin : TEXCOORD4;
float2 CustomData : TEXCOORD5; // x-per-geometry type, y-features mask
#if USE_CUSTOM_VERTEX_INTERPOLATORS #if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9; float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif #endif
@@ -69,7 +67,6 @@ struct MaterialInput
float3 WorldPosition; float3 WorldPosition;
float TwoSidedSign; float TwoSidedSign;
float2 TexCoord; float2 TexCoord;
float2 CustomData; // x-per-geometry type, y-features mask
#if USE_VERTEX_COLOR #if USE_VERTEX_COLOR
half4 VertexColor; half4 VertexColor;
#endif #endif
@@ -87,7 +84,6 @@ MaterialInput GetMaterialInput(Render2DVertex input, VertexOutput output)
MaterialInput result; MaterialInput result;
result.WorldPosition = output.WorldPosition; result.WorldPosition = output.WorldPosition;
result.TexCoord = output.TexCoord; result.TexCoord = output.TexCoord;
result.CustomData = input.CustomDataAndClipOrigin.xy;
#if USE_VERTEX_COLOR #if USE_VERTEX_COLOR
result.VertexColor = output.VertexColor; result.VertexColor = output.VertexColor;
#endif #endif
@@ -107,7 +103,6 @@ MaterialInput GetMaterialInput(PixelInput input)
MaterialInput result; MaterialInput result;
result.WorldPosition = input.WorldPosition; result.WorldPosition = input.WorldPosition;
result.TexCoord = input.TexCoord; result.TexCoord = input.TexCoord;
result.CustomData = input.CustomData;
#if USE_VERTEX_COLOR #if USE_VERTEX_COLOR
result.VertexColor = input.VertexColor; result.VertexColor = input.VertexColor;
#endif #endif
@@ -234,7 +229,6 @@ VertexOutput VS_GUI(Render2DVertex input)
#if USE_VERTEX_COLOR #if USE_VERTEX_COLOR
output.VertexColor = input.Color; output.VertexColor = input.Color;
#endif #endif
output.CustomData = input.CustomDataAndClipOrigin.xy;
output.ClipOrigin = input.CustomDataAndClipOrigin.zw; output.ClipOrigin = input.CustomDataAndClipOrigin.zw;
output.ClipExtents = input.ClipExtents; output.ClipExtents = input.ClipExtents;

View File

@@ -8,7 +8,6 @@
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl" #include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl" #include "./Flax/GBufferCommon.hlsl"
#include "./Flax/VolumetricFog.hlsl"
@7 @7
// Primary constant buffer (with additional material parameters) // Primary constant buffer (with additional material parameters)
@@ -22,7 +21,6 @@ float Dummy0;
float VolumetricFogMaxDistance; float VolumetricFogMaxDistance;
int ParticleStride; int ParticleStride;
int ParticleIndex; int ParticleIndex;
float4 GridSliceParameters;
@1META_CB_END @1META_CB_END
// Particles attributes buffer // Particles attributes buffer
@@ -204,19 +202,19 @@ Material GetMaterialPS(MaterialInput input)
META_PS(true, FEATURE_LEVEL_SM5) META_PS(true, FEATURE_LEVEL_SM5)
void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out float4 VBufferB : SV_Target1) void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out float4 VBufferB : SV_Target1)
{ {
// Reproject grid position back to the screen and world space
uint3 gridCoordinate = uint3(input.Vertex.Position.xy, input.LayerIndex); uint3 gridCoordinate = uint3(input.Vertex.Position.xy, input.LayerIndex);
float3 cellOffset = 0.5f; float3 cellOffset = 0.5f;
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy; float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
float sceneDepth = GetDepthFromSlice(GridSliceParameters, gridCoordinate.z + cellOffset.z) / ViewFar; float zSlice = gridCoordinate.z + cellOffset.z;
float sceneDepth = (zSlice / GridSize.z) * VolumetricFogMaxDistance / ViewFar;
float deviceDepth = (ViewInfo.w / sceneDepth) + ViewInfo.z; float deviceDepth = (ViewInfo.w / sceneDepth) + ViewInfo.z;
float4 clipPos = float4(volumeUV * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0); float4 clipPos = float4(volumeUV * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0);
float4 wsPos = mul(clipPos, InverseViewProjectionMatrix); float4 wsPos = mul(clipPos, InverseViewProjectionMatrix);
wsPos.xyz /= wsPos.w; float3 positionWS = wsPos.xyz / wsPos.w;
// Get material parameters // Get material parameters
MaterialInput materialInput = (MaterialInput)0; MaterialInput materialInput = (MaterialInput)0;
materialInput.WorldPosition = wsPos.xyz; materialInput.WorldPosition = positionWS;
materialInput.TexCoord = input.Vertex.TexCoord; materialInput.TexCoord = input.Vertex.TexCoord;
materialInput.ParticleIndex = ParticleIndex; materialInput.ParticleIndex = ParticleIndex;
materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1)); materialInput.TBN = float3x3(float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1));
@@ -227,10 +225,9 @@ void PS_VolumetricFog(Quad_GS2PS input, out float4 VBufferA : SV_Target0, out fl
Material material = GetMaterialPS(materialInput); Material material = GetMaterialPS(materialInput);
// Compute fog properties // Compute fog properties
material.Opacity *= material.Mask;
float3 albedo = material.Color; float3 albedo = material.Color;
float extinction = material.Opacity * 0.001f; float extinction = material.Opacity * material.Mask * 0.001f;
float3 emission = material.Emissive * material.Opacity; float3 emission = material.Emissive;
float3 scattering = albedo * extinction; float3 scattering = albedo * extinction;
float absorption = max(0.0f, extinction - Luminance(scattering)); float absorption = max(0.0f, extinction - Luminance(scattering));

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/SpriteMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/TexturePreviewMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Wires Debug Material.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Engine/DefaultMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultRadialMenu.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultTerrainMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SingleColorMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SkyboxMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/ColorGrading.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Fog.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GI/DDGI.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:615dff65b01507be6c4de722e126324aba20fc197f8e12dafaa94a05e46cba6e oid sha256:0f34bf867df5f4296ca66ac691c2bca4efa168fb9e21ca4e613e8086669575cf
size 13222 size 13296

BIN
Content/Shaders/GUI.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1f07ebb16820897e8598ae7a0627cb75b3d28e9dceea3ad4bd9ff543d5cdd01c oid sha256:064f54786958f109222c49cbc0358ff4f345b30010fcd5e8cc1fab7bdc68c4fe
size 13979 size 13349

BIN
Content/Shaders/Histogram.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Lights.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/MultiScaler.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/PostProcessing.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Reflections.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/SSAO.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/SSR.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Sky.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/TAA.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:706adde844360c2b0e65ecabaf1d2e2cc4eb4ac7ca9d483d0dd04ec8163b3d97 oid sha256:872ac3560279bfd0aeb989ebac1b49750dd142b985bc40058888dfd2b63fe9b2
size 13081 size 13214

View File

@@ -2,18 +2,17 @@
"Name": "Flax", "Name": "Flax",
"Version": { "Version": {
"Major": 1, "Major": 1,
"Minor": 12, "Minor": 11,
"Revision": 0, "Revision": 0,
"Build": 6905 "Build": 6805
}, },
"Company": "Flax", "Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.", "Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
"GameTarget": "FlaxGame", "GameTarget": "FlaxGame",
"EditorTarget": "FlaxEditor", "EditorTarget": "FlaxEditor",
"Configuration": { "Configuration": {
"UseCSharp": true, "UseCSharp": true,
"UseLargeWorlds": false, "UseLargeWorlds": false,
"UseDotNet": true, "UseDotNet": true
"UseSDL": true
} }
} }

View File

@@ -188,7 +188,7 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_CASE_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_CASE_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>

View File

@@ -12,6 +12,6 @@ cd "`dirname "$0"`"
bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@" bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations # Build bindings for all editor configurations
#echo Building C# bindings... echo Building C# bindings...
# TODO: Detect the correct architecture here # TODO: Detect the correct architecture here
#Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor

View File

@@ -187,11 +187,6 @@ namespace FlaxEditor.Content.Import
// Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular // Glossiness, metalness, ambient occlusion, displacement, height, cavity or specular
_settings.Settings.Type = TextureFormatType.GrayScale; _settings.Settings.Type = TextureFormatType.GrayScale;
} }
else if (_settings.Settings.Type == TextureFormatType.ColorRGB)
{
// Blind guess that common color texture is sRGB
_settings.Settings.sRGB = true;
}
// Try to restore target asset texture import options (useful for fast reimport) // Try to restore target asset texture import options (useful for fast reimport)
Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl); Editor.TryRestoreImportOptions(ref _settings.Settings, ResultUrl);

View File

@@ -282,7 +282,7 @@ namespace FlaxEditor.Content
if (data is DragDataFiles) if (data is DragDataFiles)
return DragDropEffect.Copy; return DragDropEffect.Copy;
return _dragOverItems?.Effect ?? DragDropEffect.None; return _dragOverItems.Effect;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -20,7 +20,7 @@ namespace FlaxEditor.Content
} }
/// <inheritdoc /> /// <inheritdoc />
public override string TypeDescription => Path.EndsWith(".h") || Path.EndsWith(".hpp") ? "C++ Header File" : "C++ Source Code"; public override string TypeDescription => Path.EndsWith(".h") ? "C++ Header File" : "C++ Source Code";
/// <inheritdoc /> /// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128; public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128;

View File

@@ -21,12 +21,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (Values.HasDifferentTypes == false) if (Values.HasDifferentTypes == false)
{ {
var group = layout.Group("Probe"); var group = layout.Group("Bake");
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2); group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
_bake = group.Button("Bake").Button; _bake = group.Button("Bake").Button;
_bake.Clicked += BakeButtonClicked; _bake.Clicked += BakeButtonClicked;
var view = group.Button("View", "Opens the probe texture viewer");
view.Button.Clicked += OnViewButtonClicked;
} }
} }
@@ -52,14 +50,5 @@ namespace FlaxEditor.CustomEditors.Dedicated
} }
} }
} }
private void OnViewButtonClicked()
{
foreach (var value in Values)
{
if (value is EnvironmentProbe probe && probe.ProbeAsset)
Editor.Instance.ContentEditing.Open(probe.ProbeAsset);
}
}
} }
} }

View File

@@ -190,12 +190,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
foreach (var file in files) foreach (var file in files)
FindNewKeysCSharp(file, newKeys, allKeys); FindNewKeysCSharp(file, newKeys, allKeys);
// C/C++ // C++
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.c", SearchOption.AllDirectories)).ToArray(); files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories);
filesCount += files.Length; filesCount += files.Length;
foreach (var file in files) foreach (var file in files)
FindNewKeysCpp(file, newKeys, allKeys); FindNewKeysCpp(file, newKeys, allKeys);
files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories).Concat(Directory.GetFiles(Globals.ProjectSourceFolder, "*.hpp", SearchOption.AllDirectories)).ToArray(); files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories);
filesCount += files.Length; filesCount += files.Length;
foreach (var file in files) foreach (var file in files)
FindNewKeysCpp(file, newKeys, allKeys); FindNewKeysCpp(file, newKeys, allKeys);

View File

@@ -1,38 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Custom editor for <see cref="NavMeshBoundsVolume"/>.
/// </summary>
/// <seealso cref="ActorEditor" />
[CustomEditor(typeof(NavMeshBoundsVolume)), DefaultEditor]
internal class NavMeshBoundsVolumeEditor : ActorEditor
{
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
if (Values.HasDifferentTypes == false)
{
var button = layout.Button("Build");
button.Button.Clicked += OnBuildClicked;
}
}
private void OnBuildClicked()
{
foreach (var value in Values)
{
if (value is NavMeshBoundsVolume volume)
{
Navigation.BuildNavMesh(volume.Box, volume.Scene);
Editor.Instance.Scene.MarkSceneEdited(volume.Scene);
}
}
}
}
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection.Emit;
using FlaxEditor.CustomEditors.GUI; using FlaxEditor.CustomEditors.GUI;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;

View File

@@ -909,8 +909,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
settingsButton.Tag = script; settingsButton.Tag = script;
settingsButton.Clicked += OnSettingsButtonClicked; settingsButton.Clicked += OnSettingsButtonClicked;
// Adjust margin to not overlap with other ui elements in the header group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
group.Panel.HeaderTextMargin = group.Panel.HeaderTextMargin with { Left = scriptDrag.Right - 12, Right = settingsButton.Width + Utilities.Constants.UIMargin };
group.Object(values, editor); group.Object(values, editor);
// Remove drop down arrows and containment lines if no objects in the group // Remove drop down arrows and containment lines if no objects in the group
if (group.Children.Count == 0) if (group.Children.Count == 0)

View File

@@ -450,7 +450,6 @@ namespace FlaxEditor.CustomEditors.Editors
protected bool NotNullItems; protected bool NotNullItems;
private IntValueBox _sizeBox; private IntValueBox _sizeBox;
private Label _label;
private Color _background; private Color _background;
private int _elementsCount, _minCount, _maxCount; private int _elementsCount, _minCount, _maxCount;
private bool _readOnly; private bool _readOnly;
@@ -567,7 +566,7 @@ namespace FlaxEditor.CustomEditors.Editors
Parent = dropPanel, Parent = dropPanel,
}; };
_label = new Label var label = new Label
{ {
Text = "Size", Text = "Size",
AnchorPreset = AnchorPresets.TopRight, AnchorPreset = AnchorPresets.TopRight,
@@ -593,12 +592,11 @@ namespace FlaxEditor.CustomEditors.Editors
panel.Panel.Offsets = new Margin(7, 7, 0, 0); panel.Panel.Offsets = new Margin(7, 7, 0, 0);
panel.Panel.BackgroundColor = _background; panel.Panel.BackgroundColor = _background;
var elementType = ElementType; var elementType = ElementType;
var bindingAttr = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public;
bool single = elementType.IsPrimitive || bool single = elementType.IsPrimitive ||
elementType.Equals(new ScriptType(typeof(string))) || elementType.Equals(new ScriptType(typeof(string))) ||
elementType.IsEnum || elementType.IsEnum ||
(elementType.GetFields(bindingAttr).Length == 1 && elementType.GetProperties(bindingAttr).Length == 0) || (elementType.GetFields().Length == 1 && elementType.GetProperties().Length == 0) ||
(elementType.GetProperties(bindingAttr).Length == 1 && elementType.GetFields(bindingAttr).Length == 0) || (elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
elementType.Equals(new ScriptType(typeof(JsonAsset))) || elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
elementType.Equals(new ScriptType(typeof(SettingsBase))); elementType.Equals(new ScriptType(typeof(SettingsBase)));
if (_cachedDropPanels == null) if (_cachedDropPanels == null)
@@ -674,8 +672,6 @@ namespace FlaxEditor.CustomEditors.Editors
Resize(Count + 1); Resize(Count + 1);
}; };
} }
Layout.ContainerControl.SizeChanged += OnLayoutSizeChanged;
} }
private void OnSetupContextMenu(ContextMenu menu, DropPanel panel) private void OnSetupContextMenu(ContextMenu menu, DropPanel panel)
@@ -700,24 +696,10 @@ namespace FlaxEditor.CustomEditors.Editors
}); });
} }
private void OnLayoutSizeChanged(Control control)
{
if (Layout.ContainerControl is DropPanel dropPanel)
{
// Hide "Size" text when array editor title overlaps
var headerTextSize = dropPanel.HeaderTextFont.GetFont().MeasureText(dropPanel.HeaderText);
if (headerTextSize.X + DropPanel.DropDownIconSize >= _label.Left)
_label.TextColor = _label.TextColorHighlighted = Color.Transparent;
else
_label.TextColor = _label.TextColorHighlighted = FlaxEngine.GUI.Style.Current.Foreground;
}
}
/// <inheritdoc /> /// <inheritdoc />
protected override void Deinitialize() protected override void Deinitialize()
{ {
_sizeBox = null; _sizeBox = null;
Layout.ContainerControl.SizeChanged -= OnLayoutSizeChanged;
base.Deinitialize(); base.Deinitialize();
} }

View File

@@ -47,8 +47,6 @@ namespace FlaxEditor.CustomEditors.Editors
return inputEvent; return inputEvent;
if (Values[0] is string str) if (Values[0] is string str)
return str; return str;
if (Values.Type.Type == typeof(InputEvent))
return new InputEvent();
if (Values.Type.Type == typeof(string)) if (Values.Type.Type == typeof(string))
return string.Empty; return string.Empty;
return null; return null;

View File

@@ -44,8 +44,7 @@ namespace FlaxEditor.CustomEditors.Elements
{ {
var style = Style.Current; var style = Style.Current;
var settingsButtonSize = Panel.HeaderHeight; var settingsButtonSize = Panel.HeaderHeight;
Panel.HeaderTextMargin = Panel.HeaderTextMargin with { Right = settingsButtonSize + Utilities.Constants.UIMargin }; return new Image
; return new Image
{ {
TooltipText = "Settings", TooltipText = "Settings",
AutoFocus = true, AutoFocus = true,

View File

@@ -23,7 +23,6 @@ using FlaxEngine.Assertions;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Interop; using FlaxEngine.Interop;
using FlaxEngine.Json; using FlaxEngine.Json;
using FlaxEngine.Utilities;
#pragma warning disable CS1591 #pragma warning disable CS1591
@@ -1371,7 +1370,7 @@ namespace FlaxEditor
public void BuildCSG() public void BuildCSG()
{ {
var scenes = Level.Scenes; var scenes = Level.Scenes;
scenes.ForEach(x => x.BuildCSG(0)); scenes.ToList().ForEach(x => x.BuildCSG(0));
Scene.MarkSceneEdited(scenes); Scene.MarkSceneEdited(scenes);
} }
@@ -1381,7 +1380,7 @@ namespace FlaxEditor
public void BuildNavMesh() public void BuildNavMesh()
{ {
var scenes = Level.Scenes; var scenes = Level.Scenes;
Navigation.BuildNavMesh(); scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
Scene.MarkSceneEdited(scenes); Scene.MarkSceneEdited(scenes);
} }

View File

@@ -502,7 +502,6 @@ namespace FlaxEditor.GUI.ContextMenu
if (base.OnKeyDown(key)) if (base.OnKeyDown(key))
return true; return true;
// Keyboard navigation around the menu
switch (key) switch (key)
{ {
case KeyboardKeys.ArrowDown: case KeyboardKeys.ArrowDown:
@@ -527,20 +526,6 @@ namespace FlaxEditor.GUI.ContextMenu
} }
} }
break; break;
case KeyboardKeys.ArrowRight:
for (int i = 0; i < _panel.Children.Count; i++)
{
if (_panel.Children[i] is ContextMenuChildMenu item && item.Visible && item.IsFocused && !item.ContextMenu.IsOpened)
{
item.ShowChild(this);
item.ContextMenu._panel.Children.FirstOrDefault(x => x is ContextMenuButton && x.Visible)?.Focus();
break;
}
}
break;
case KeyboardKeys.ArrowLeft:
ParentCM?.RootWindow.Focus();
break;
} }
return false; return false;

View File

@@ -1,10 +1,7 @@
#if PLATFORM_WINDOWS || PLATFORM_SDL #if PLATFORM_WINDOWS
#define USE_IS_FOREGROUND #define USE_IS_FOREGROUND
#else #else
#endif #endif
#if PLATFORM_SDL
#define USE_SDL_WORKAROUNDS
#endif
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic; using System.Collections.Generic;
@@ -75,11 +72,6 @@ namespace FlaxEditor.GUI.ContextMenu
/// </summary> /// </summary>
public bool HasChildCMOpened => _childCM != null; public bool HasChildCMOpened => _childCM != null;
/// <summary>
/// Gets the parent context menu (if exists).
/// </summary>
public ContextMenuBase ParentCM => _parentCM;
/// <summary> /// <summary>
/// Gets the topmost context menu. /// Gets the topmost context menu.
/// </summary> /// </summary>
@@ -89,7 +81,9 @@ namespace FlaxEditor.GUI.ContextMenu
{ {
var cm = this; var cm = this;
while (cm._parentCM != null && cm._isSubMenu) while (cm._parentCM != null && cm._isSubMenu)
{
cm = cm._parentCM; cm = cm._parentCM;
}
return cm; return cm;
} }
} }
@@ -114,11 +108,6 @@ namespace FlaxEditor.GUI.ContextMenu
/// </summary> /// </summary>
public bool UseInput = true; public bool UseInput = true;
/// <summary>
/// Optional flag that can disable UI navigation (tab/enter).
/// </summary>
public bool UseNavigation = true;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContextMenuBase"/> class. /// Initializes a new instance of the <see cref="ContextMenuBase"/> class.
/// </summary> /// </summary>
@@ -133,7 +122,7 @@ namespace FlaxEditor.GUI.ContextMenu
} }
/// <summary> /// <summary>
/// Shows the empty menu popup on a screen. /// Shows the empty menu popup o na screen.
/// </summary> /// </summary>
/// <param name="control">The target control.</param> /// <param name="control">The target control.</param>
/// <param name="area">The target control area to cover.</param> /// <param name="area">The target control area to cover.</param>
@@ -268,9 +257,7 @@ namespace FlaxEditor.GUI.ContextMenu
desc.AllowMaximize = false; desc.AllowMaximize = false;
desc.AllowDragAndDrop = false; desc.AllowDragAndDrop = false;
desc.IsTopmost = true; desc.IsTopmost = true;
desc.Type = WindowType.Popup; desc.IsRegularWindow = false;
desc.Parent = parentWin.Window;
desc.Title = "ContextMenu";
desc.HasSizingFrame = false; desc.HasSizingFrame = false;
OnWindowCreating(ref desc); OnWindowCreating(ref desc);
_window = Platform.CreateWindow(ref desc); _window = Platform.CreateWindow(ref desc);
@@ -280,12 +267,6 @@ namespace FlaxEditor.GUI.ContextMenu
_window.LostFocus += OnWindowLostFocus; _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 // Attach to the window
_parentCM = parent as ContextMenuBase; _parentCM = parent as ContextMenuBase;
Parent = _window.GUI; Parent = _window.GUI;
@@ -460,17 +441,6 @@ 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() private void OnWindowGotFocus()
{ {
var child = _childCM; var child = _childCM;
@@ -484,7 +454,6 @@ namespace FlaxEditor.GUI.ContextMenu
}); });
} }
} }
#endif
private void OnWindowLostFocus() private void OnWindowLostFocus()
{ {
@@ -583,12 +552,7 @@ namespace FlaxEditor.GUI.ContextMenu
// Let root context menu to check if none of the popup windows // Let root context menu to check if none of the popup windows
if (_parentCM == null && UseVisibilityControl && !IsForeground) if (_parentCM == null && UseVisibilityControl && !IsForeground)
{ {
#if USE_SDL_WORKAROUNDS
if (!IsMouseOver)
Hide();
#else
Hide(); Hide();
#endif
} }
} }
#endif #endif
@@ -630,21 +594,6 @@ namespace FlaxEditor.GUI.ContextMenu
case KeyboardKeys.Escape: case KeyboardKeys.Escape:
Hide(); Hide();
return true; return true;
case KeyboardKeys.Return:
if (UseNavigation && Root?.FocusedControl != null)
{
Root.SubmitFocused();
return true;
}
break;
case KeyboardKeys.Tab:
if (UseNavigation && Root != null)
{
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
return true;
}
break;
} }
return false; return false;
} }

View File

@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI.ContextMenu
CloseMenuOnClick = false; CloseMenuOnClick = false;
} }
internal void ShowChild(ContextMenu parentContextMenu) private void ShowChild(ContextMenu parentContextMenu)
{ {
// Hide parent CM popups and set itself as child // Hide parent CM popups and set itself as child
var vAlign = parentContextMenu.ItemsAreaMargin.Top; var vAlign = parentContextMenu.ItemsAreaMargin.Top;

View File

@@ -522,16 +522,6 @@ namespace FlaxEditor.GUI
cm.AddButton("Show whole curve", _editor.ShowWholeCurve); cm.AddButton("Show whole curve", _editor.ShowWholeCurve);
cm.AddButton("Reset view", _editor.ResetView); cm.AddButton("Reset view", _editor.ResetView);
} }
cm.AddSeparator();
var presetCm = cm.AddChildMenu("Apply preset");
foreach (var value in Enum.GetValues(typeof(CurvePreset)))
{
CurvePreset preset = (CurvePreset)value;
string name = Utilities.Utils.GetPropertyNameUI(preset.ToString());
var b = presetCm.ContextMenu.AddButton(name, () => _editor.ApplyPreset(preset));
b.Enabled = !(_editor is LinearCurveEditor<T> && (preset != CurvePreset.Constant && preset != CurvePreset.Linear));
}
_editor.OnShowContextMenu(cm, selectionCount); _editor.OnShowContextMenu(cm, selectionCount);
cm.Show(this, location); cm.Show(this, location);
} }
@@ -629,33 +619,6 @@ namespace FlaxEditor.GUI
} }
} }
/// <summary>
/// A list of avaliable curve presets for the <see cref="CurveEditor{T}"/>.
/// </summary>
public enum CurvePreset
{
/// <summary>
/// A curve where every point has the same value.
/// </summary>
Constant,
/// <summary>
/// A curve linear curve.
/// </summary>
Linear,
/// <summary>
/// A curve that starts a slowly and then accelerates until the end.
/// </summary>
EaseIn,
/// <summary>
/// A curve that starts a steep and then flattens until the end.
/// </summary>
EaseOut,
/// <summary>
/// A combination of the <see cref="CurvePreset.EaseIn"/> and <see cref="CurvePreset.EaseOut"/> preset.
/// </summary>
Smoothstep
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnKeyframesDeselect(IKeyframesEditor editor) public override void OnKeyframesDeselect(IKeyframesEditor editor)
{ {

View File

@@ -19,48 +19,6 @@ namespace FlaxEditor.GUI
/// <seealso cref="CurveEditorBase" /> /// <seealso cref="CurveEditorBase" />
public abstract partial class CurveEditor<T> : CurveEditorBase where T : new() public abstract partial class CurveEditor<T> : CurveEditorBase where T : new()
{ {
/// <summary>
/// Represents a single point in a <see cref="CurveEditorPreset"/>.
/// </summary>
protected struct CurvePresetPoint
{
/// <summary>
/// The time.
/// </summary>
public float Time;
/// <summary>
/// The value.
/// </summary>
public float Value;
/// <summary>
/// The in tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
/// </summary>
public float TangentIn;
/// <summary>
/// The out tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
/// </summary>
public float TangentOut;
}
/// <summary>
/// A curve preset.
/// </summary>
protected struct CurveEditorPreset()
{
/// <summary>
/// If the tangents will be linear or smooth.
/// </summary>
public bool LinearTangents;
/// <summary>
/// The points of the preset.
/// </summary>
public List<CurvePresetPoint> Points;
}
private class Popup : ContextMenuBase private class Popup : ContextMenuBase
{ {
private CustomEditorPresenter _presenter; private CustomEditorPresenter _presenter;
@@ -68,12 +26,11 @@ namespace FlaxEditor.GUI
private List<int> _keyframeIndices; private List<int> _keyframeIndices;
private bool _isDirty; private bool _isDirty;
public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float maxHeight = 140.0f) public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float height = 140.0f)
: this(editor, maxHeight) : this(editor, height)
{ {
_presenter.Select(selection); _presenter.Select(selection);
_presenter.OpenAllGroups(); _presenter.OpenAllGroups();
Size = new Float2(Size.X, Mathf.Min(_presenter.ContainerControl.Size.Y, maxHeight));
_keyframeIndices = keyframeIndices; _keyframeIndices = keyframeIndices;
if (keyframeIndices != null && selection.Length != keyframeIndices.Count) if (keyframeIndices != null && selection.Length != keyframeIndices.Count)
throw new Exception(); throw new Exception();
@@ -212,7 +169,7 @@ namespace FlaxEditor.GUI
if (IsSelected) if (IsSelected)
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f); color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
if (IsMouseOver) if (IsMouseOver)
color *= 1.5f; color *= 1.1f;
Render2D.FillRectangle(rect, color); Render2D.FillRectangle(rect, color);
} }
@@ -328,7 +285,7 @@ namespace FlaxEditor.GUI
/// <summary> /// <summary>
/// The keyframes size. /// The keyframes size.
/// </summary> /// </summary>
protected static readonly Float2 KeyframesSize = new Float2(8.0f); protected static readonly Float2 KeyframesSize = new Float2(7.0f);
/// <summary> /// <summary>
/// The colors for the keyframe points. /// The colors for the keyframe points.
@@ -369,63 +326,6 @@ namespace FlaxEditor.GUI
private Color _labelsColor; private Color _labelsColor;
private Font _labelsFont; private Font _labelsFont;
/// <summary>
/// Preset values for <see cref="CurvePreset"/> to be applied to a <see cref="CurveEditor{T}"/>.
/// </summary>
protected Dictionary<CurvePreset, CurveEditorPreset> Presets = new Dictionary<CurvePreset, CurveEditorPreset>
{
{ CurvePreset.Constant, new CurveEditorPreset
{
LinearTangents = true,
Points = new List<CurvePresetPoint>
{
new CurvePresetPoint { Time = 0f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
new CurvePresetPoint { Time = 1f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
}
}
},
{ CurvePreset.EaseIn, new CurveEditorPreset
{
LinearTangents = false,
Points = new List<CurvePresetPoint>
{
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = -1.4f, TangentOut = 0f },
}
}
},
{ CurvePreset.EaseOut, new CurveEditorPreset
{
LinearTangents = false,
Points = new List<CurvePresetPoint>
{
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 1.4f },
}
}
},
{ CurvePreset.Linear, new CurveEditorPreset
{
LinearTangents = true,
Points = new List<CurvePresetPoint>
{
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
}
}
},
{ CurvePreset.Smoothstep, new CurveEditorPreset
{
LinearTangents = false,
Points = new List<CurvePresetPoint>
{
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
}
}
},
};
/// <summary> /// <summary>
/// The keyframe UI points. /// The keyframe UI points.
/// </summary> /// </summary>
@@ -668,28 +568,6 @@ namespace FlaxEditor.GUI
/// <param name="indicesToRemove">The list of indices of the keyframes to remove.</param> /// <param name="indicesToRemove">The list of indices of the keyframes to remove.</param>
protected abstract void RemoveKeyframesInternal(HashSet<int> indicesToRemove); protected abstract void RemoveKeyframesInternal(HashSet<int> indicesToRemove);
/// <summary>
/// Tries to convert a float to the type of the type wildcard of the curve editor.
/// </summary>
/// <param name="value">The float.</param>
/// <returns>The converted value.</returns>
public static object ConvertCurvePresetValueToCurveEditorType(float value)
{
if (typeof(T) == typeof(Float2))
return new Float2(value);
if (typeof(T) == typeof(Float3))
return new Float3(value);
if (typeof(T) == typeof(Float4))
return new Float4(value);
if (typeof(T) == typeof(Vector2))
return new Vector2(value);
if (typeof(T) == typeof(Vector3))
return new Vector3(value);
if (typeof(T) == typeof(Vector4))
return new Vector4(value);
return value;
}
/// <summary> /// <summary>
/// Called when showing a context menu. Can be used to add custom buttons with actions. /// Called when showing a context menu. Can be used to add custom buttons with actions.
/// </summary> /// </summary>
@@ -874,17 +752,6 @@ namespace FlaxEditor.GUI
ShowCurve(false); ShowCurve(false);
} }
/// <summary>
/// Applies a <see cref="CurvePreset"/> to the curve editor.
/// </summary>
/// <param name="preset">The preset.</param>
public virtual void ApplyPreset(CurvePreset preset)
{
// Remove existing keyframes
SelectAll();
RemoveKeyframes();
}
/// <inheritdoc /> /// <inheritdoc />
public override void Evaluate(out object result, float time, bool loop = false) public override void Evaluate(out object result, float time, bool loop = false)
{ {
@@ -1161,31 +1028,6 @@ namespace FlaxEditor.GUI
return true; return true;
} }
bool left = key == KeyboardKeys.ArrowLeft;
bool right = key == KeyboardKeys.ArrowRight;
bool up = key == KeyboardKeys.ArrowUp;
bool down = key == KeyboardKeys.ArrowDown;
if (left || right || up || down)
{
bool shift = Root.GetKey(KeyboardKeys.Shift);
bool alt = Root.GetKey(KeyboardKeys.Alt);
float deltaValue = 10f;
if (shift || alt)
deltaValue = shift ? 2.5f : 5f;
Float2 moveDelta = Float2.Zero;
if (left || right)
moveDelta.X = left ? -deltaValue : deltaValue;
if (up || down)
moveDelta.Y = up ? -deltaValue : deltaValue;
_contents.OnMoveStart(Float2.Zero);
_contents.OnMove(moveDelta);
_contents.OnMoveEnd(Float2.Zero);
return true;
}
return false; return false;
} }
@@ -1684,22 +1526,6 @@ namespace FlaxEditor.GUI
_tangents[i].Visible = false; _tangents[i].Visible = false;
} }
/// <inheritdoc />
public override void ApplyPreset(CurvePreset preset)
{
base.ApplyPreset(preset);
CurveEditorPreset data = Presets[preset];
foreach (var point in data.Points)
{
float time = point.Time;
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
AddKeyframe(time, value);
}
ShowWholeCurve();
}
/// <inheritdoc /> /// <inheritdoc />
protected override void DrawCurve(ref Rectangle viewRect) protected override void DrawCurve(ref Rectangle viewRect)
{ {
@@ -2486,30 +2312,6 @@ namespace FlaxEditor.GUI
} }
} }
/// <inheritdoc />
public override void ApplyPreset(CurvePreset preset)
{
base.ApplyPreset(preset);
CurveEditorPreset data = Presets[preset];
foreach (var point in data.Points)
{
float time = point.Time;
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
object tangentIn = ConvertCurvePresetValueToCurveEditorType((float)point.TangentIn);
object tangentOut = ConvertCurvePresetValueToCurveEditorType((float)point.TangentOut);
AddKeyframe(time, value, tangentIn, tangentOut);
}
SelectAll();
if (data.LinearTangents)
SetTangentsLinear();
ShowWholeCurve();
}
/// <inheritdoc /> /// <inheritdoc />
protected override void SetScaleInternal(ref Float2 scale) protected override void SetScaleInternal(ref Float2 scale)
{ {

View File

@@ -41,7 +41,6 @@ namespace FlaxEditor.GUI.Dialogs
private bool _useDynamicEditing; private bool _useDynamicEditing;
private bool _activeEyedropper; private bool _activeEyedropper;
private bool _canPassLastChangeEvent = true; private bool _canPassLastChangeEvent = true;
private bool _linear;
private ColorValueBox.ColorPickerEvent _onChanged; private ColorValueBox.ColorPickerEvent _onChanged;
private ColorValueBox.ColorPickerClosedEvent _onClosed; private ColorValueBox.ColorPickerClosedEvent _onClosed;
@@ -57,7 +56,6 @@ namespace FlaxEditor.GUI.Dialogs
private Button _cCancel; private Button _cCancel;
private Button _cOK; private Button _cOK;
private Button _cEyedropper; private Button _cEyedropper;
private Button _cLinearSRGB;
private List<Color> _savedColors = new List<Color>(); private List<Color> _savedColors = new List<Color>();
private List<Button> _savedColorButtons = new List<Button>(); private List<Button> _savedColorButtons = new List<Button>();
@@ -120,7 +118,6 @@ namespace FlaxEditor.GUI.Dialogs
_value = Color.Transparent; _value = Color.Transparent;
_onChanged = colorChanged; _onChanged = colorChanged;
_onClosed = pickerClosed; _onClosed = pickerClosed;
_linear = !Graphics.GammaColorSpace;
// Get saved colors if they exist // Get saved colors if they exist
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out string savedColors)) if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out string savedColors))
@@ -230,25 +227,6 @@ namespace FlaxEditor.GUI.Dialogs
_cEyedropper.Width = _cEyedropper.Height; _cEyedropper.Width = _cEyedropper.Height;
_cEyedropper.X -= _cEyedropper.Width; _cEyedropper.X -= _cEyedropper.Width;
// Linear/sRGB toggle button
_cLinearSRGB = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin)
{
TooltipText = "Toggles between color preview in Linear and sRGB",
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.SplineAligned64),
BackgroundColor = _cEyedropper.BackgroundColor,
BackgroundColorHighlighted = _cEyedropper.BackgroundColorHighlighted,
BorderColor = _linear ? Color.Transparent : style.Foreground,
BorderColorHighlighted = _cEyedropper.BorderColorHighlighted,
Size = _cEyedropper.Size,
Parent = this,
Location = _cEyedropper.BottomLeft + new Float2(0, 4),
};
_cLinearSRGB.Clicked += () =>
{
_linear = !_linear;
_cLinearSRGB.BorderColor = _linear ? Color.Transparent : style.Foreground;
};
// Set initial color // Set initial color
SelectedColor = initialValue; SelectedColor = initialValue;
} }
@@ -303,22 +281,16 @@ namespace FlaxEditor.GUI.Dialogs
if (_activeEyedropper) if (_activeEyedropper)
{ {
_activeEyedropper = false; _activeEyedropper = false;
if (colorPicked != Color.Transparent) SelectedColor = colorPicked;
{ ScreenUtilities.PickColorDone -= OnColorPicked;
Color color = colorPicked;
if (_linear)
color = color.ToLinear();
SelectedColor = color;
}
Platform.PickScreenColorDone -= OnColorPicked;
} }
} }
private void OnEyedropStart() private void OnEyedropStart()
{ {
_activeEyedropper = true; _activeEyedropper = true;
Platform.PickScreenColor(); ScreenUtilities.PickColor();
Platform.PickScreenColorDone += OnColorPicked; ScreenUtilities.PickColorDone += OnColorPicked;
} }
private void OnRGBAChanged() private void OnRGBAChanged()
@@ -354,15 +326,8 @@ namespace FlaxEditor.GUI.Dialogs
// Update eye dropper tool // Update eye dropper tool
if (_activeEyedropper) if (_activeEyedropper)
{ {
// Try reading the color under the cursor in realtime if supported by the platform
Float2 mousePosition = Platform.MousePosition; Float2 mousePosition = Platform.MousePosition;
Color color = Platform.GetScreenColorAt(mousePosition); SelectedColor = ScreenUtilities.GetColorAt(mousePosition);
if (color != Color.Transparent)
{
if (_linear)
color = color.ToLinear();
SelectedColor = color;
}
} }
} }
@@ -423,7 +388,7 @@ namespace FlaxEditor.GUI.Dialogs
} }
} }
} }
Render2D.FillRectangle(newRect, _linear ? _value.ToSRgb() : _value); Render2D.FillRectangle(newRect, _value);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -444,7 +409,7 @@ namespace FlaxEditor.GUI.Dialogs
{ {
// Cancel eye dropping // Cancel eye dropping
_activeEyedropper = false; _activeEyedropper = false;
Platform.PickScreenColorDone -= OnColorPicked; ScreenUtilities.PickColorDone -= OnColorPicked;
return true; return true;
} }

View File

@@ -310,26 +310,6 @@ namespace FlaxEditor.GUI.Dialogs
Render2D.DrawRectangle(_slider1Rect, _isMouseDownSlider1 ? style.BackgroundSelected : Color.Black); Render2D.DrawRectangle(_slider1Rect, _isMouseDownSlider1 ? style.BackgroundSelected : Color.Black);
Render2D.DrawRectangle(valueR, _isMouseDownSlider1 ? Color.White : Color.Gray); Render2D.DrawRectangle(valueR, _isMouseDownSlider1 ? Color.White : Color.Gray);
// Draw checkerboard pattern to part of the alpha slider background
var alphaRect = _slider2Rect;
Render2D.FillRectangle(alphaRect, Color.White);
var smallRectSize = alphaRect.Width * 0.5f;
var numHor = Mathf.CeilToInt(alphaRect.Width / smallRectSize);
var numVer = Mathf.CeilToInt(alphaRect.Height / smallRectSize);
for (int i = 0; i < numHor; i++)
{
for (int j = 0; j < numVer; j++)
{
if ((i + j) % 2 == 0)
{
var rect = new Rectangle(alphaRect.X + smallRectSize * i, alphaRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.PushClip(alphaRect);
Render2D.FillRectangle(rect, Color.Gray);
Render2D.PopClip();
}
}
}
// Alpha // Alpha
float alphaY = _slider2Rect.Height * (1 - _color.A); float alphaY = _slider2Rect.Height * (1 - _color.A);
var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness); var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);

View File

@@ -0,0 +1,545 @@
// 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 += Editor.Instance.Options.Options.Interface.TabHeight;
result.Size.Y -= Editor.Instance.Options.Options.Interface.TabHeight;
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;
}
}
}
}
}

View File

@@ -469,7 +469,7 @@ namespace FlaxEditor.GUI.Docking
var childPanels = _childPanels.ToArray(); var childPanels = _childPanels.ToArray();
if (childPanels.Length != 0) if (childPanels.Length != 0)
{ {
// Fallback: move tabs from child panels into this one. // Move tabs from child panels into this one
DockWindow selectedTab = null; DockWindow selectedTab = null;
foreach (var childPanel in childPanels) foreach (var childPanel in childPanels)
{ {
@@ -490,8 +490,7 @@ namespace FlaxEditor.GUI.Docking
{ {
// Unlink splitter // Unlink splitter
var splitterParent = splitter.Parent; var splitterParent = splitter.Parent;
if (splitterParent == null) Assert.IsNotNull(splitterParent);
return;
splitter.Parent = null; splitter.Parent = null;
// Move controls from second split panel to the split panel parent // Move controls from second split panel to the split panel parent
@@ -508,63 +507,17 @@ namespace FlaxEditor.GUI.Docking
splitter.Dispose(); splitter.Dispose();
} }
} }
else if (IsMaster && _childPanels.Count != 0)
{
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
return;
}
else if (!IsMaster) else if (!IsMaster)
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
} }
else if (_childPanels.Count != 0)
{
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
return;
}
else if (!IsMaster) else if (!IsMaster)
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
} }
internal bool CollapseEmptyTabsProxy()
{
if (TabsCount == 0 && ChildPanelsCount > 0)
{
return TryCollapseSplitter(_tabsProxy?.Parent as Panel);
}
return false;
}
private bool TryCollapseSplitter(Panel removedPanelParent)
{
if (removedPanelParent == null)
return false;
if (!(removedPanelParent.Parent is SplitPanel tabsSplitter))
return false;
var splitterParent = tabsSplitter.Parent;
if (splitterParent == null)
return false;
tabsSplitter.Parent = null;
var scrPanel = removedPanelParent == tabsSplitter.Panel2 ? tabsSplitter.Panel1 : tabsSplitter.Panel2;
var srcPanelChildrenCount = scrPanel.ChildrenCount;
for (int i = srcPanelChildrenCount - 1; i >= 0 && scrPanel.ChildrenCount > 0; i--)
{
scrPanel.GetChild(i).Parent = splitterParent;
}
Assert.IsTrue(scrPanel.ChildrenCount == 0);
Assert.IsTrue(splitterParent.ChildrenCount == srcPanelChildrenCount);
tabsSplitter.Dispose();
if (_tabsProxy != null && _tabsProxy.Parent == removedPanelParent)
_tabsProxy = null;
return true;
}
internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null) internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
{ {
DockWindow(state, window, autoSelect, splitterValue); DockWindow(state, window, autoSelect, splitterValue);

View File

@@ -19,7 +19,11 @@ namespace FlaxEditor.GUI.Docking
private float _tabHeight = Editor.Instance.Options.Options.Interface.TabHeight; private float _tabHeight = Editor.Instance.Options.Options.Interface.TabHeight;
private bool _useMinimumTabWidth = Editor.Instance.Options.Options.Interface.UseMinimumTabWidth; private bool _useMinimumTabWidth = Editor.Instance.Options.Options.Interface.UseMinimumTabWidth;
private float _minimumTabWidth = Editor.Instance.Options.Options.Interface.MinimumTabWidth; private float _minimumTabWidth = Editor.Instance.Options.Options.Interface.MinimumTabWidth;
private readonly bool _hideTabForSingleTab = Utilities.Utils.HideSingleTabWindowTabBars(); #if PLATFORM_WINDOWS
private readonly bool _hideTabForSingleTab = Editor.Instance.Options.Options.Interface.HideSingleTabWindowTabBars;
#else
private readonly bool _hideTabForSingleTab = false;
#endif
/// <summary> /// <summary>
/// The is mouse down flag (left button). /// The is mouse down flag (left button).
@@ -51,11 +55,6 @@ namespace FlaxEditor.GUI.Docking
/// </summary> /// </summary>
public Float2 MousePosition = Float2.Minimum; public Float2 MousePosition = Float2.Minimum;
/// <summary>
/// The mouse position.
/// </summary>
public Float2 MouseStartPosition = Float2.Minimum;
/// <summary> /// <summary>
/// The start drag asynchronous window. /// The start drag asynchronous window.
/// </summary> /// </summary>
@@ -197,7 +196,7 @@ namespace FlaxEditor.GUI.Docking
if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating) if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating)
{ {
// Create docking hint window but in an async manner // Create docking hint window but in an async manner
WindowDragHelper.StartDragging(_panel as FloatWindowDockPanel); DockHintWindow.Create(_panel as FloatWindowDockPanel);
} }
else else
{ {
@@ -208,7 +207,7 @@ namespace FlaxEditor.GUI.Docking
_panel.SelectTab(index - 1); _panel.SelectTab(index - 1);
// Create docking hint window // Create docking hint window
WindowDragHelper.StartDragging(win, _panel.RootWindow.Window); DockHintWindow.Create(win);
} }
} }
} }
@@ -394,7 +393,6 @@ namespace FlaxEditor.GUI.Docking
if (IsSingleFloatingWindow) if (IsSingleFloatingWindow)
return base.OnMouseDown(location, button); return base.OnMouseDown(location, button);
MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross); MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross);
MouseStartPosition = location;
// Check buttons // Check buttons
if (button == MouseButton.Left) if (button == MouseButton.Left)
@@ -481,20 +479,6 @@ namespace FlaxEditor.GUI.Docking
StartDrag(MouseDownWindow); StartDrag(MouseDownWindow);
MouseDownWindow = null; 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 // Check if has more than one tab to change order
else if (MouseDownWindow != null && _panel.TabsCount > 1) else if (MouseDownWindow != null && _panel.TabsCount > 1)
{ {

View File

@@ -182,26 +182,6 @@ namespace FlaxEditor.GUI.Docking
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param> /// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
/// <param name="position">Window location.</param> /// <param name="position">Window location.</param>
public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent) 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(); Undock();
@@ -219,17 +199,14 @@ namespace FlaxEditor.GUI.Docking
windowGUI.UnlockChildrenRecursive(); windowGUI.UnlockChildrenRecursive();
windowGUI.PerformLayout(); windowGUI.PerformLayout();
if (showWindow) // Show
{ window.Show();
// Show window.BringToFront();
window.Show(); window.Focus();
window.BringToFront(); OnShow();
window.Focus();
OnShow();
// Perform layout again // Perform layout again
windowGUI.PerformLayout(); windowGUI.PerformLayout();
}
} }
/// <summary> /// <summary>

View File

@@ -11,42 +11,6 @@ namespace FlaxEditor.GUI.Docking
/// <seealso cref="DockPanel" /> /// <seealso cref="DockPanel" />
public class FloatWindowDockPanel : DockPanel public class FloatWindowDockPanel : DockPanel
{ {
private class FloatWindowDecorations : WindowDecorations
{
private FloatWindowDockPanel _panel;
public FloatWindowDecorations(FloatWindowDockPanel panel)
: base(panel.RootWindow)
{
_panel = panel;
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (Title.Bounds.Contains(location) && button == MouseButton.Left)
{
_panel.BeginDrag();
return true;
}
return base.OnMouseDown(location, button);
}
#if !PLATFORM_WINDOWS
/// <inheritdoc />
protected override WindowHitCodes OnHitTest(ref Float2 mouse)
{
var hit = base.OnHitTest(ref mouse);
if (hit == WindowHitCodes.Caption)
{
// Override the system behaviour when interacting with the caption area
hit = WindowHitCodes.Client;
}
return hit;
}
#endif
}
private MasterDockPanel _masterPanel; private MasterDockPanel _masterPanel;
private WindowRootControl _window; private WindowRootControl _window;
@@ -76,26 +40,6 @@ namespace FlaxEditor.GUI.Docking
Parent = window; Parent = window;
_window.Window.Closing += OnClosing; _window.Window.Closing += OnClosing;
_window.Window.LeftButtonHit += OnLeftButtonHit; _window.Window.LeftButtonHit += OnLeftButtonHit;
if (Utilities.Utils.UseCustomWindowDecorations())
{
var decorations = Parent.AddChild(new FloatWindowDecorations(this));
decorations.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false);
}
}
/// <inheritdoc />
protected override void PerformLayoutBeforeChildren()
{
base.PerformLayoutBeforeChildren();
var decorations = Parent.GetChild<FloatWindowDecorations>();
if (decorations != null)
{
// Apply offset for the title bar
foreach (var child in Children)
child.Bounds = child.Bounds with { Y = decorations.Height, Height = Parent.Height - decorations.Height };
}
} }
/// <summary> /// <summary>
@@ -108,11 +52,7 @@ namespace FlaxEditor.GUI.Docking
return; return;
// Create docking hint window // Create docking hint window
Window dragSourceWindow = null; DockHintWindow.Create(this);
#if !PLATFORM_SDL
dragSourceWindow = _window?.Window;
#endif
WindowDragHelper.StartDragging(this, dragSourceWindow);
} }
/// <summary> /// <summary>
@@ -131,33 +71,23 @@ namespace FlaxEditor.GUI.Docking
settings.Title = title; settings.Title = title;
settings.Size = size; settings.Size = size;
settings.Position = location; settings.Position = location;
settings.MinimumSize = new Float2(100, 100); settings.MinimumSize = new Float2(1);
settings.MaximumSize = Float2.Zero; // Unlimited size settings.MaximumSize = Float2.Zero; // Unlimited size
settings.Fullscreen = false; settings.Fullscreen = false;
settings.HasBorder = true; settings.HasBorder = true;
#if PLATFORM_SDL
settings.SupportsTransparency = true;
#else
settings.SupportsTransparency = false; settings.SupportsTransparency = false;
#endif
settings.ActivateWhenFirstShown = true; settings.ActivateWhenFirstShown = true;
settings.AllowInput = true; settings.AllowInput = true;
settings.AllowMinimize = true; settings.AllowMinimize = true;
settings.AllowMaximize = true; settings.AllowMaximize = true;
settings.AllowDragAndDrop = true; settings.AllowDragAndDrop = true;
settings.IsTopmost = false; settings.IsTopmost = false;
settings.Type = WindowType.Regular; settings.IsRegularWindow = true;
settings.HasSizingFrame = true; settings.HasSizingFrame = true;
settings.ShowAfterFirstPaint = false; settings.ShowAfterFirstPaint = false;
settings.ShowInTaskbar = true; settings.ShowInTaskbar = true;
settings.StartPosition = startPosition; settings.StartPosition = startPosition;
if (Utilities.Utils.UseCustomWindowDecorations())
{
settings.HasBorder = false;
//settings.HasSizingFrame = false;
}
// Create window // Create window
return Platform.CreateWindow(ref settings); return Platform.CreateWindow(ref settings);
} }
@@ -221,12 +151,7 @@ namespace FlaxEditor.GUI.Docking
base.OnSelectedTabChanged(); base.OnSelectedTabChanged();
if (_window != null && SelectedTab != null) if (_window != null && SelectedTab != null)
{
_window.Title = SelectedTab.Title; _window.Title = SelectedTab.Title;
var decorations = Parent.GetChild<FloatWindowDecorations>();
if (decorations != null)
decorations.PerformLayout();
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -81,6 +81,7 @@ namespace FlaxEditor.GUI.Docking
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded) public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
{ {
// Check all floating windows // Check all floating windows
// TODO: gather windows order and take it into account when performing test
for (int i = 0; i < FloatingPanels.Count; i++) for (int i = 0; i < FloatingPanels.Count; i++)
{ {
var win = FloatingPanels[i]; var win = FloatingPanels[i];
@@ -93,44 +94,9 @@ namespace FlaxEditor.GUI.Docking
} }
// Base // Base
//if (!Root?.RootWindow.Window.IsFocused ?? false)
// return null;
return base.HitTest(ref position); 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) internal void LinkWindow(DockWindow window)
{ {
// Add to the windows list // Add to the windows list

View File

@@ -1,514 +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 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 = 48.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;
var mousePos = Platform.MousePosition;
// Check if window is maximized and restore window for correct dragging
if (window.IsMaximized)
{
var windowMousePos = mousePos - window.Position;
var previousSize = window.Size;
window.Restore();
window.Position = mousePos - windowMousePos * window.Size / previousSize;
}
// When drag starts from a tabs the window might not be shown yet
if (!window.IsVisible)
{
window.Show();
window.Position = mousePos - new Float2(40, 10);
}
// Bind events
FlaxEngine.Scripting.Update += OnUpdate;
window.MouseUp += OnMouseUp;
#if !PLATFORM_SDL
window.StartTrackingMouse(false);
#endif
// Update rectangles
UpdateRects(mousePos);
// 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
{
#if PLATFORM_SDL
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
#else
_dragOffset = mousePos - window.Position;
#endif
// The mouse up event is sent to the source window on Windows
_dragSourceWindow.MouseUp += OnMouseUp;
// 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);
#if !PLATFORM_SDL
_dragSourceWindow.BringToFront();
#endif
}
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 !PLATFORM_SDL
window.EndTrackingMouse();
#endif
}
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>
/// <param name="dragSourceWindow">The window where dragging started from.</param>
/// <returns>The window drag helper object.</returns>
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove, Window dragSourceWindow = null)
{
if (toMove == null)
throw new ArgumentNullException();
return new WindowDragHelper(toMove, dragSourceWindow);
}
/// <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
// TODO: this doesn't allow docking window into another floating window over the main window
/*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
if (_toDock != Editor.Instance.UI.MasterPanel)
_toDock?.RootWindow.Window.BringToFront();
//_toDock?.RootWindow.Window.Focus();
#if PLATFORM_SDL
// Make the dragged window transparent when dock hints are visible
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
#else
// Bring the drop source always to the top
if (_dragSourceWindow != null)
_dragSourceWindow.BringToFront();
#endif
}
// Check dock state to use
bool showProxyHints = _toDock != null;
bool showBorderHints = showProxyHints;
bool showCenterHint = showProxyHints;
Control hoveredHintControl = null;
Float2 hoveredLocationOffset = Float2.Zero;
Float2 hoveredSizeOverride = Float2.Zero;
DockState prevToSet = _toSet;
float hoveredMargin = 1.0f;
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 = 10.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
var toSet = DockState.Float;
var hintTestPoint = _toDock.PointFromScreen(_mouse);
if (showBorderHints)
{
if (_rUpper.Contains(ref hintTestPoint))
{
toSet = DockState.DockTop;
hoveredHintControl = _dockHintUp;
hoveredSizeOverride = new Float2(size.X, size.Y * DockPanel.DefaultSplitterValue);
hoveredLocationOffset.Y -= borderMargin - hoveredMargin;
}
else if (_rBottom.Contains(ref hintTestPoint))
{
toSet = DockState.DockBottom;
hoveredHintControl = _dockHintDown;
hoveredSizeOverride = new Float2(size.X, size.Y * DockPanel.DefaultSplitterValue);
hoveredLocationOffset.Y += borderMargin - hoveredMargin;
}
else if (_rLeft.Contains(ref hintTestPoint))
{
toSet = DockState.DockLeft;
hoveredHintControl = _dockHintLeft;
hoveredSizeOverride = new Float2(size.X * DockPanel.DefaultSplitterValue, size.Y);
hoveredLocationOffset.X -= borderMargin - hoveredMargin;
}
else if (_rRight.Contains(ref hintTestPoint))
{
toSet = DockState.DockRight;
hoveredHintControl = _dockHintRight;
hoveredSizeOverride = new Float2(size.X * DockPanel.DefaultSplitterValue, size.Y);
hoveredLocationOffset.X += borderMargin - hoveredMargin;
}
}
if (showCenterHint && _rCenter.Contains(ref hintTestPoint))
{
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)
{
var mainColor = Style.Current.Selection;
if (hoveredHintControl != _dockHintDown)
{
_dockHintDown.Size = new Float2(HintControlSize);
_dockHintDown.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintLeft)
{
_dockHintLeft.Size = new Float2(HintControlSize);
_dockHintLeft.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintRight)
{
_dockHintRight.Size = new Float2(HintControlSize);
_dockHintRight.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintUp)
{
_dockHintUp.Size = new Float2(HintControlSize);
_dockHintUp.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintCenter)
{
_dockHintCenter.Size = new Float2(HintControlSize);
_dockHintCenter.BackgroundColor = mainColor.AlphaMultiplied(0.6f);
}
if (_toSet != DockState.Float)
{
if (hoveredHintControl != null)
{
hoveredHintControl.BackgroundColor = mainColor;
if (_toSet != prevToSet)
hoveredHintControl.Location += hoveredLocationOffset;
hoveredHintControl.Size = hoveredSizeOverride - hoveredMargin;
}
}
}
// 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()
{
// If the engine lost focus during dragging, end the action
if (!Engine.HasFocus)
{
Dispose();
return;
}
var mousePos = Platform.MousePosition;
if (_mouse != mousePos)
{
if (_dragSourceWindow != null)
_toMove.Window.Window.Position = mousePos - _dragOffset;
UpdateRects(mousePos);
}
}
}
}

View File

@@ -242,15 +242,6 @@ namespace FlaxEditor.GUI
{ {
FieldInfo[] fields = type.GetFields(); FieldInfo[] fields = type.GetFields();
entries.Capacity = Mathf.Max(fields.Length - 1, entries.Capacity); entries.Capacity = Mathf.Max(fields.Length - 1, entries.Capacity);
if (formatMode == EnumDisplayAttribute.FormatMode.Default)
{
// Override display mode from enum itself
var attr = type.GetCustomAttribute<EnumDisplayAttribute>();
if (attr != null)
{
formatMode = attr.Mode;
}
}
for (int i = 0; i < fields.Length; i++) for (int i = 0; i < fields.Length; i++)
{ {
var field = fields[i]; var field = fields[i];

View File

@@ -15,7 +15,6 @@ namespace FlaxEditor.GUI.Input
public class ColorValueBox : Control public class ColorValueBox : Control
{ {
private bool _isMouseDown; private bool _isMouseDown;
private bool _linear;
/// <summary> /// <summary>
/// Delegate function used for the color picker events handling. /// Delegate function used for the color picker events handling.
@@ -102,7 +101,6 @@ namespace FlaxEditor.GUI.Input
public ColorValueBox() public ColorValueBox()
: base(0, 0, 32, 18) : base(0, 0, 32, 18)
{ {
_linear = !Graphics.GammaColorSpace;
} }
/// <summary> /// <summary>
@@ -115,7 +113,6 @@ namespace FlaxEditor.GUI.Input
: base(x, y, 32, 18) : base(x, y, 32, 18)
{ {
_value = value; _value = value;
_linear = !Graphics.GammaColorSpace;
} }
/// <summary> /// <summary>
@@ -132,10 +129,8 @@ namespace FlaxEditor.GUI.Input
{ {
base.Draw(); base.Draw();
var value = _value; bool isTransparent = _value.A < 1;
if (_linear)
value = value.ToSRgb();
var isTransparent = value.A < 1;
var style = Style.Current; var style = Style.Current;
var fullRect = new Rectangle(0, 0, Width, Height); var fullRect = new Rectangle(0, 0, Width, Height);
var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height); var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height);
@@ -162,10 +157,10 @@ namespace FlaxEditor.GUI.Input
} }
} }
} }
Render2D.FillRectangle(alphaRect, value); Render2D.FillRectangle(alphaRect, _value);
} }
Render2D.FillRectangle(colorRect, value with { A = 1 }); Render2D.FillRectangle(colorRect, _value with { A = 1 });
Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black); Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
} }

View File

@@ -99,11 +99,6 @@ namespace FlaxEditor.GUI.Input
/// </summary> /// </summary>
public event Action SlidingEnd; public event Action SlidingEnd;
/// <summary>
/// If enabled, pressing the arrow up or down key increments/ decrements the value.
/// </summary>
public bool ArrowKeysIncrement = true;
/// <summary> /// <summary>
/// Gets or sets the slider speed. Use value 0 to disable and hide slider UI. /// Gets or sets the slider speed. Use value 0 to disable and hide slider UI.
/// </summary> /// </summary>
@@ -244,27 +239,6 @@ namespace FlaxEditor.GUI.Input
ResetViewOffset(); ResetViewOffset();
} }
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (ArrowKeysIncrement && (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown))
{
bool altDown = Root.GetKey(KeyboardKeys.Alt);
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
bool controlDown = Root.GetKey(KeyboardKeys.Control);
float deltaValue = altDown ? 0.1f : (shiftDown ? 10f : (controlDown ? 100f : 1f));
float slideDelta = key == KeyboardKeys.ArrowUp ? deltaValue : -deltaValue;
_startSlideValue = Value;
ApplySliding(slideDelta);
EndSliding();
Focus();
return true;
}
return base.OnKeyDown(key);
}
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button) public override bool OnMouseDown(Float2 location, MouseButton button)
{ {
@@ -292,7 +266,6 @@ namespace FlaxEditor.GUI.Input
return base.OnMouseDown(location, button); return base.OnMouseDown(location, button);
} }
#if !PLATFORM_SDL
/// <inheritdoc /> /// <inheritdoc />
public override void OnMouseMove(Float2 location) public override void OnMouseMove(Float2 location)
{ {
@@ -319,45 +292,13 @@ namespace FlaxEditor.GUI.Input
base.OnMouseMove(location); base.OnMouseMove(location);
} }
#else
/// <inheritdoc />
public override void OnMouseMoveRelative(Float2 motion)
{
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(motion);
}
#endif
/// <inheritdoc /> /// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button) public override bool OnMouseUp(Float2 location, MouseButton button)
{ {
if (button == MouseButton.Left && _isSliding) if (button == MouseButton.Left && _isSliding)
{ {
#if !PLATFORM_SDL
// End sliding and return mouse to original location // End sliding and return mouse to original location
RootWindow.MousePosition = _mouseClickedPosition; RootWindow.MousePosition = _mouseClickedPosition;
#endif
EndSliding(); EndSliding();
return true; return true;
} }

View File

@@ -59,12 +59,12 @@ namespace FlaxEditor.GUI
/// <summary> /// <summary>
/// Occurs when items gets clicked by the user. /// Occurs when items gets clicked by the user.
/// </summary> /// </summary>
public event Action<Item> ItemClicked; public event Action<Item> Clicked;
/// <summary> /// <summary>
/// Occurs when items gets focused. /// Occurs when items gets focused.
/// </summary> /// </summary>
public event Action<Item> ItemFocused; public event Action<Item> Focused;
/// <summary> /// <summary>
/// The tint color of the text. /// The tint color of the text.
@@ -203,7 +203,7 @@ namespace FlaxEditor.GUI
if (button == MouseButton.Left && _isMouseDown) if (button == MouseButton.Left && _isMouseDown)
{ {
_isMouseDown = false; _isMouseDown = false;
ItemClicked?.Invoke(this); Clicked?.Invoke(this);
} }
return base.OnMouseUp(location, button); return base.OnMouseUp(location, button);
@@ -222,7 +222,7 @@ namespace FlaxEditor.GUI
{ {
base.OnGotFocus(); base.OnGotFocus();
ItemFocused?.Invoke(this); Focused?.Invoke(this);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -434,7 +434,7 @@ namespace FlaxEditor.GUI
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
public void AddItem(Item item) public void AddItem(Item item)
{ {
item.ItemClicked += OnClickItem; item.Clicked += OnClickItem;
ContainerControl parent = ItemsPanel; ContainerControl parent = ItemsPanel;
if (!string.IsNullOrEmpty(item.Category)) if (!string.IsNullOrEmpty(item.Category))
{ {

View File

@@ -12,6 +12,16 @@ namespace FlaxEditor.GUI
/// <seealso cref="FlaxEngine.GUI.ContainerControl" /> /// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public sealed class MainMenu : ContainerControl public sealed class MainMenu : ContainerControl
{ {
#if PLATFORM_WINDOWS
private bool _useCustomWindowSystem;
private Image _icon;
private Label _title;
private Button _closeButton;
private Button _minimizeButton;
private Button _maximizeButton;
private LocalizedString _charChromeRestore, _charChromeMaximize;
private Window _window;
#endif
private MainMenuButton _selected; private MainMenuButton _selected;
/// <summary> /// <summary>
@@ -50,12 +60,200 @@ namespace FlaxEditor.GUI
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MainMenu"/> class. /// Initializes a new instance of the <see cref="MainMenu"/> class.
/// </summary> /// </summary>
public MainMenu() /// <param name="mainWindow">The main window.</param>
public MainMenu(RootControl mainWindow)
: base(0, 0, 0, 20) : base(0, 0, 0, 20)
{ {
AutoFocus = false; AutoFocus = false;
AnchorPreset = AnchorPresets.HorizontalStretchTop; AnchorPreset = AnchorPresets.HorizontalStretchTop;
BackgroundColor = Style.Current.LightBackground;
#if PLATFORM_WINDOWS
_useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
if (_useCustomWindowSystem)
{
BackgroundColor = Style.Current.LightBackground;
Height = 28;
var windowIcon = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.WindowIcon);
FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.WindowIconsFont);
Font iconFont = windowIconsFont?.CreateFont(9);
_window = mainWindow.RootWindow.Window;
_window.HitTest += OnHitTest;
_window.Closed += OnWindowClosed;
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
_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),
Parent = this,
};
_title = new Label(0, 0, Width, Height)
{
Text = _window.Title,
HorizontalAlignment = TextAlignment.Center,
VerticalAlignment = TextAlignment.Center,
ClipText = true,
TextColor = Style.Current.ForegroundGrey,
TextColorHighlighted = Style.Current.ForegroundGrey,
Parent = this,
};
_closeButton = new Button
{
Text = ((char)EditorAssets.SegMDL2Icons.ChromeClose).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Color.Transparent,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Color.Red,
BackgroundColorSelected = Color.Red.RGBMultiplied(1.3f),
Parent = this,
};
_closeButton.Clicked += () => _window.Close(ClosingReason.User);
_minimizeButton = new Button
{
Text = ((char)EditorAssets.SegMDL2Icons.ChromeMinimize).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Color.Transparent,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f),
Parent = this,
};
_minimizeButton.Clicked += () => _window.Minimize();
_maximizeButton = new Button
{
Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Color.Transparent,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f),
Parent = this,
};
_maximizeButton.Clicked += () =>
{
if (_window.IsMaximized)
_window.Restore();
else
_window.Maximize();
};
_charChromeRestore = ((char)EditorAssets.SegMDL2Icons.ChromeRestore).ToString();
_charChromeMaximize = ((char)EditorAssets.SegMDL2Icons.ChromeMaximize).ToString();
}
else
#endif
{
BackgroundColor = Style.Current.LightBackground;
}
}
#if PLATFORM_WINDOWS
/// <inheritdoc />
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (_maximizeButton != null)
{
_maximizeButton.Text = _window.IsMaximized ? _charChromeRestore : _charChromeMaximize;
}
}
private void OnWindowClosed()
{
if (_window != null)
{
_window.HitTest = null;
_window = null;
}
}
private WindowHitCodes OnHitTest(ref Float2 mouse)
{
var dpiScale = _window.DpiScale;
if (_window.IsMinimized)
return WindowHitCodes.NoWhere;
if (!_window.IsMaximized)
{
var pos = _window.ScreenToClient(mouse * dpiScale); // pos is not DPI adjusted
var winSize = _window.Size;
// Distance from which the mouse is considered to be on the border/corner
float distance = 5.0f * dpiScale;
if (pos.Y > winSize.Y - distance && pos.X < distance)
return WindowHitCodes.BottomLeft;
if (pos.X > winSize.X - distance && pos.Y > winSize.Y - distance)
return WindowHitCodes.BottomRight;
if (pos.Y < distance && pos.X < distance)
return WindowHitCodes.TopLeft;
if (pos.Y < distance && pos.X > winSize.X - distance)
return WindowHitCodes.TopRight;
if (pos.X > winSize.X - distance)
return WindowHitCodes.Right;
if (pos.X < distance)
return WindowHitCodes.Left;
if (pos.Y < distance)
return WindowHitCodes.Top;
if (pos.Y > winSize.Y - distance)
return WindowHitCodes.Bottom;
}
var mousePos = PointFromScreen(mouse * dpiScale);
var controlUnderMouse = GetChildAt(mousePos);
var isMouseOverSth = controlUnderMouse != null && controlUnderMouse != _title;
var rb = GetRightButton();
if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight, _minimizeButton.BottomLeft - rb.UpperRight).Contains(ref mousePos) && !isMouseOverSth)
return WindowHitCodes.Caption;
return WindowHitCodes.Client;
}
#endif
/// <summary>
/// Return the rightmost button.
/// </summary>
/// <returns>Rightmost button, null if there is no <see cref="MainMenuButton"/></returns>
private MainMenuButton GetRightButton()
{
MainMenuButton b = null;
foreach (var control in Children)
{
if (b == null && control is MainMenuButton)
b = (MainMenuButton)control;
if (control is MainMenuButton && control.Right > b.Right)
b = (MainMenuButton)control;
}
return b;
} }
/// <summary> /// <summary>
@@ -100,6 +298,26 @@ namespace FlaxEditor.GUI
return result; return result;
} }
/// <inheritdoc />
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{
if (base.OnMouseDoubleClick(location, button))
return true;
#if PLATFORM_WINDOWS
var child = GetChildAtRecursive(location);
if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
{
if (_window.IsMaximized)
_window.Restore();
else
_window.Maximize();
}
#endif
return true;
}
/// <inheritdoc /> /// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key) public override bool OnKeyDown(KeyboardKeys key)
{ {
@@ -115,8 +333,16 @@ namespace FlaxEditor.GUI
protected override void PerformLayoutAfterChildren() protected override void PerformLayoutAfterChildren()
{ {
float x = 0; float x = 0;
WindowDecorations decorations = Parent.GetChild<WindowDecorations>();
x += decorations?.Icon?.Width ?? 0; #if PLATFORM_WINDOWS
if (_useCustomWindowSystem)
{
// Icon
_icon.X = x;
_icon.Size = new Float2(Height);
x += _icon.Width;
}
#endif
// Arrange controls // Arrange controls
MainMenuButton rightMostButton = null; MainMenuButton rightMostButton = null;
@@ -136,20 +362,36 @@ namespace FlaxEditor.GUI
} }
} }
// Fill the right side if title and buttons are not present #if PLATFORM_WINDOWS
if (decorations?.Title == null) if (_useCustomWindowSystem)
Width = Parent.Width; {
else // Buttons
Width = x; _closeButton.Height = Height;
_closeButton.X = Width - _closeButton.Width;
_maximizeButton.Height = Height;
_maximizeButton.X = _closeButton.X - _maximizeButton.Width;
_minimizeButton.Height = Height;
_minimizeButton.X = _maximizeButton.X - _minimizeButton.Width;
// Title
_title.Bounds = new Rectangle(x + 2, 0, _minimizeButton.Left - x - 4, Height);
//_title.Text = _title.Width < 300.0f ? Editor.Instance.ProjectInfo.Name : _window.Title;
}
#endif
} }
#if PLATFORM_WINDOWS
/// <inheritdoc /> /// <inheritdoc />
public override void OnDestroy() public override void OnDestroy()
{ {
base.OnDestroy(); base.OnDestroy();
if (_selected != null) if (_window != null)
Selected = null; {
_window.Closed -= OnWindowClosed;
OnWindowClosed();
}
} }
#endif
} }
} }

View File

@@ -42,12 +42,14 @@ namespace FlaxEditor.GUI
Text = text; Text = text;
var style = Style.Current; var style = Style.Current;
if (!Utilities.Utils.UseCustomWindowDecorations()) #if PLATFORM_WINDOWS
if (Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
{ {
BackgroundColorMouseOver = style.BackgroundHighlighted; BackgroundColorMouseOver = style.BackgroundHighlighted;
BackgroundColorMouseOverOpened = style.Background; BackgroundColorMouseOverOpened = style.Background;
} }
else else
#endif
{ {
BackgroundColorMouseOver = BackgroundColorMouseOverOpened = style.LightBackground * 1.3f; BackgroundColorMouseOver = BackgroundColorMouseOverOpened = style.LightBackground * 1.3f;
} }

View File

@@ -1140,11 +1140,8 @@ namespace FlaxEditor.GUI.Tree
ParentTree.DraggedOverNode = this; ParentTree.DraggedOverNode = this;
// Expand node if mouse goes over arrow // Expand node if mouse goes over arrow
if (ArrowRect.Contains(location) && HasAnyVisibleChild && IsCollapsed) if (ArrowRect.Contains(location) && HasAnyVisibleChild)
{
Expand(true); Expand(true);
ParentTree?.FlushPendingPerformLayout();
}
result = OnDragEnterHeader(data); result = OnDragEnterHeader(data);
} }
@@ -1175,11 +1172,8 @@ namespace FlaxEditor.GUI.Tree
ParentTree.DraggedOverNode = this; ParentTree.DraggedOverNode = this;
// Expand node if mouse goes over arrow // Expand node if mouse goes over arrow
if (ArrowRect.Contains(location) && HasAnyVisibleChild && IsCollapsed) if (ArrowRect.Contains(location) && HasAnyVisibleChild)
{
Expand(true); Expand(true);
ParentTree?.FlushPendingPerformLayout();
}
if (!_isDragOverHeader) if (!_isDragOverHeader)
result = OnDragEnterHeader(data); result = OnDragEnterHeader(data);

View File

@@ -1,339 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI;
/// <summary>
/// Represents the title bar of the window with buttons.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public class WindowDecorations : ContainerControl
{
private Image _icon;
private Label _title;
private Button _closeButton;
private Button _minimizeButton;
private Button _maximizeButton;
private LocalizedString _charChromeRestore, _charChromeMaximize;
private Window _window;
/// <summary>
/// The title label in the title bar.
/// </summary>
public Label Title => _title;
/// <summary>
/// The icon used in the title bar.
/// </summary>
public Image Icon => _icon;
/// <summary>
/// The tooltip shown when hovering over the icon.
/// </summary>
public string IconTooltipText
{
get => _icon?.TooltipText ?? null;
set
{
if (_icon != null)
_icon.TooltipText = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="WindowDecorations"/> class.
/// </summary>
/// <param name="window">The window.</param>
/// <param name="iconOnly">When set, omit drawing title and buttons.</param>
public WindowDecorations(RootControl window, bool iconOnly = false)
: base(0, 0, 0, 20)
{
_window = window.RootWindow.Window;
AutoFocus = false;
AnchorPreset = AnchorPresets.HorizontalStretchTop;
BackgroundColor = Color.Transparent;
var windowIcon = FlaxEngine.Content.LoadAsyncInternal<Texture>(EditorAssets.WindowIcon);
_icon = new Image
{
Margin = new Margin(4, 4, 4, 4),
Brush = new TextureBrush(windowIcon),
Color = Style.Current.Foreground,
BackgroundColor = Style.Current.LightBackground,
KeepAspectRatio = false,
Parent = this,
};
if (!iconOnly)
{
_icon.Margin = new Margin(6, 6, 6, 6);
Height = 28;
_window.HitTest += OnHitTest;
_window.Closed += OnWindowClosed;
FontAsset windowIconsFont = FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.WindowIconsFont);
Font iconFont = windowIconsFont?.CreateFont(9);
_title = new Label(0, 0, Width, Height)
{
Text = _window.Title,
HorizontalAlignment = TextAlignment.Center,
VerticalAlignment = TextAlignment.Center,
ClipText = true,
TextColor = Style.Current.ForegroundGrey,
TextColorHighlighted = Style.Current.ForegroundGrey,
BackgroundColor = Style.Current.LightBackground,
Parent = this,
};
_closeButton = new Button
{
Text = ((char)EditorAssets.SegMDL2Icons.ChromeClose).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Style.Current.LightBackground,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Color.Red,
BackgroundColorSelected = Color.Red.RGBMultiplied(1.3f),
Parent = this,
};
_closeButton.Clicked += () => _window.Close(ClosingReason.User);
_minimizeButton = new Button
{
Text = ((char)EditorAssets.SegMDL2Icons.ChromeMinimize).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Style.Current.LightBackground,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f),
Parent = this,
};
_minimizeButton.Clicked += () => _window.Minimize();
_maximizeButton = new Button
{
Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString(),
Font = new FontReference(iconFont),
BackgroundColor = Style.Current.LightBackground,
BorderColor = Color.Transparent,
BorderColorHighlighted = Color.Transparent,
BorderColorSelected = Color.Transparent,
TextColor = Style.Current.Foreground,
Width = 46,
BackgroundColorHighlighted = Style.Current.LightBackground.RGBMultiplied(1.3f),
Parent = this,
};
_maximizeButton.Clicked += () =>
{
if (_window.IsMaximized)
_window.Restore();
else
_window.Maximize();
};
_charChromeRestore = ((char)EditorAssets.SegMDL2Icons.ChromeRestore).ToString();
_charChromeMaximize = ((char)EditorAssets.SegMDL2Icons.ChromeMaximize).ToString();
}
}
/// <inheritdoc />
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (_maximizeButton != null)
{
var maximizeText = _window.IsMaximized ? _charChromeRestore : _charChromeMaximize;
if (_maximizeButton.Text != maximizeText)
_maximizeButton.Text = maximizeText;
}
}
private void OnWindowClosed()
{
if (_window != null)
{
_window.HitTest -= OnHitTest;
_window = null;
}
}
/// <summary>
/// Perform hit test on the window.
/// </summary>
/// <param name="mouse">The mouse position</param>
/// <returns>The hit code for given position.</returns>
protected virtual WindowHitCodes OnHitTest(ref Float2 mouse)
{
if (_window.IsMinimized)
return WindowHitCodes.NoWhere;
var dpiScale = _window.DpiScale;
var pos = _window.ScreenToClient(mouse * dpiScale); // pos is not DPI adjusted
if (!_window.IsMaximized)
{
var winSize = _window.Size;
// Distance from which the mouse is considered to be on the border/corner
float distance = 5.0f * dpiScale;
if (pos.Y > winSize.Y - distance && pos.X < distance)
return WindowHitCodes.BottomLeft;
if (pos.X > winSize.X - distance && pos.Y > winSize.Y - distance)
return WindowHitCodes.BottomRight;
if (pos.Y < distance && pos.X < distance)
return WindowHitCodes.TopLeft;
if (pos.Y < distance && pos.X > winSize.X - distance)
return WindowHitCodes.TopRight;
if (pos.X > winSize.X - distance)
return WindowHitCodes.Right;
if (pos.X < distance)
return WindowHitCodes.Left;
if (pos.Y < distance)
return WindowHitCodes.Top;
if (pos.Y > winSize.Y - distance)
return WindowHitCodes.Bottom;
}
var controlUnderMouse = GetChildAt(pos, control => control != _title);
if (_title.Bounds.Contains(pos) && controlUnderMouse == null)
return WindowHitCodes.Caption;
return WindowHitCodes.Client;
}
/// <inheritdoc />
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{
// These may not work with main window due to SDL not passing mouse events
// when interacting with hit tests on caption area...
if (Title.Bounds.Contains(location) && button == MouseButton.Left)
{
if (_window.IsMaximized)
_window.Restore();
else
_window.Maximize();
return true;
}
else if (Icon.Bounds.Contains(location) && button == MouseButton.Left)
{
_window.Close(ClosingReason.User);
return true;
}
return base.OnMouseDoubleClick(location, button);
}
/// <inheritdoc />
protected override void PerformLayoutAfterChildren()
{
// Calculate extents for title bounds area excluding the icon and main menu area
float x = 0;
// Icon
if (_icon != null)
{
_icon.X = x;
_icon.Size = new Float2(Height);
x += _icon.Width;
}
// Main menu if present
if (Parent.GetChild<MainMenu>() is MainMenu mainMenu)
{
for (int i = 0; i < mainMenu.Children.Count; i++)
{
var c = mainMenu.Children[i];
if (c is MainMenuButton b && c.Visible)
{
b.Bounds = new Rectangle(x, 0, b.Width, Height);
x += b.Width;
}
}
}
// Buttons
float rightMostButtonX = Width;
if (_closeButton != null)
{
_closeButton.Height = Height;
_closeButton.X = rightMostButtonX - _closeButton.Width;
rightMostButtonX = _closeButton.X;
}
if (_maximizeButton != null)
{
_maximizeButton.Height = Height;
_maximizeButton.X = rightMostButtonX - _maximizeButton.Width;
rightMostButtonX = _maximizeButton.X;
}
if (_minimizeButton != null)
{
_minimizeButton.Height = Height;
_minimizeButton.X = rightMostButtonX - _minimizeButton.Width;
rightMostButtonX = _minimizeButton.X;
}
// Title
if (_title != null)
{
_title.Text = _window.Title;
_title.Bounds = new Rectangle(x, 0, rightMostButtonX - x, Height);
}
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
DrawBorders();
}
/// <summary>
/// Draw borders around the window.
/// </summary>
public virtual void DrawBorders()
{
var win = RootWindow.Window;
if (win.IsMaximized)
return;
if (Editor.Instance.UI.StatusBar == null)
return;
const float thickness = 1.0f;
Color color = Editor.Instance.UI.StatusBar.StatusColor;
Rectangle rect = new Rectangle(thickness * 0.5f, thickness * 0.5f, Parent.Width - thickness, Parent.Height - thickness);
Render2D.DrawRectangle(rect, color);
}
/// <inheritdoc />
public override void OnDestroy()
{
base.OnDestroy();
if (_window != null)
{
_window.Closed -= OnWindowClosed;
OnWindowClosed();
}
}
}

View File

@@ -13,7 +13,6 @@ namespace FlaxEditor.Gizmo
public abstract class GizmoBase public abstract class GizmoBase
{ {
private IGizmoOwner _owner; private IGizmoOwner _owner;
private bool _visible = true;
/// <summary> /// <summary>
/// Gets the gizmo owner. /// Gets the gizmo owner.
@@ -35,11 +34,6 @@ namespace FlaxEditor.Gizmo
/// </summary> /// </summary>
public virtual BoundingSphere FocusBounds => BoundingSphere.Empty; public virtual BoundingSphere FocusBounds => BoundingSphere.Empty;
/// <summary>
/// Gets or sets a value indicating whether this gizmo is visible.
/// </summary>
public bool Visible { get { return _visible; } set { _visible = value; } }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GizmoBase"/> class. /// Initializes a new instance of the <see cref="GizmoBase"/> class.
/// </summary> /// </summary>

View File

@@ -36,12 +36,11 @@ public sealed class ViewportRubberBandSelector
/// Triggers the start of a rubber band selection. /// Triggers the start of a rubber band selection.
/// </summary> /// </summary>
/// <returns>True if selection started, otherwise false.</returns> /// <returns>True if selection started, otherwise false.</returns>
public bool TryStartingRubberBandSelection(Float2 mousePosition) public bool TryStartingRubberBandSelection()
{ {
if (!_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown) if (!_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
{ {
_tryStartRubberBand = true; _tryStartRubberBand = true;
_cachedStartingMousePosition = mousePosition;
return true; return true;
} }
return false; return false;
@@ -83,15 +82,12 @@ public sealed class ViewportRubberBandSelector
return; return;
} }
if (_tryStartRubberBand && canStart) if (_tryStartRubberBand && (Mathf.Abs(_owner.MouseDelta.X) > 0.1f || Mathf.Abs(_owner.MouseDelta.Y) > 0.1f) && canStart)
{ {
var delta = mousePosition - _cachedStartingMousePosition; _isRubberBandSpanning = true;
if (Mathf.Abs(delta.X) > 0.1f || Mathf.Abs(delta.Y) > 0.1f) _cachedStartingMousePosition = mousePosition;
{ _rubberBandRect = new Rectangle(_cachedStartingMousePosition, Float2.Zero);
_isRubberBandSpanning = true; _tryStartRubberBand = false;
_rubberBandRect = new Rectangle(_cachedStartingMousePosition, Float2.Zero);
_tryStartRubberBand = false;
}
} }
else if (_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown) else if (_isRubberBandSpanning && _owner.Gizmos.Active != null && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
{ {

View File

@@ -402,11 +402,10 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
break; break;
} }
} }
WindowsManager::WindowsLocker.Unlock();
for (const auto& e : inputEvents) for (const auto& e : inputEvents)
{ {
auto window = e.Target ? e.Target : defaultWindow; auto window = e.Target ? e.Target : defaultWindow;
if (!window || window->IsClosed()) if (!window)
continue; continue;
switch (e.Type) switch (e.Type)
{ {
@@ -436,14 +435,12 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
case InputDevice::EventType::MouseMove: case InputDevice::EventType::MouseMove:
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position)); window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
break; break;
case InputDevice::EventType::MouseMoveRelative:
window->OnMouseMoveRelative(e.MouseMovementData.PositionRelative);
break;
case InputDevice::EventType::MouseLeave: case InputDevice::EventType::MouseLeave:
window->OnMouseLeave(); window->OnMouseLeave();
break; break;
} }
} }
WindowsManager::WindowsLocker.Unlock();
} }
WindowsManager::WindowsLocker.Lock(); WindowsManager::WindowsLocker.Lock();
Array<Window*, InlinedAllocation<32>> windows; Array<Window*, InlinedAllocation<32>> windows;

View File

@@ -1013,7 +1013,7 @@ namespace FlaxEditor.Modules
ContentItem item; ContentItem item;
if (path.EndsWith(".cs")) if (path.EndsWith(".cs"))
item = new CSharpScriptItem(path); item = new CSharpScriptItem(path);
else if (path.EndsWith(".cpp") || path.EndsWith(".h") || path.EndsWith(".c") || path.EndsWith(".hpp")) else if (path.EndsWith(".cpp") || path.EndsWith(".h"))
item = new CppScriptItem(path); item = new CppScriptItem(path);
else if (path.EndsWith(".shader") || path.EndsWith(".hlsl")) else if (path.EndsWith(".shader") || path.EndsWith(".hlsl"))
item = new ShaderSourceItem(path); item = new ShaderSourceItem(path);

View File

@@ -222,7 +222,7 @@ namespace FlaxEditor.Modules
outputExtension = extension; outputExtension = extension;
// Check if can place source files here // Check if can place source files here
if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h" || extension == ".c" || extension == ".hpp")) if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h"))
{ {
// Error // Error
Editor.LogWarning(string.Format("Cannot import \'{0}\' to \'{1}\'. The target directory cannot have scripts.", inputPath, targetLocation.Node.Path)); Editor.LogWarning(string.Format("Cannot import \'{0}\' to \'{1}\'. The target directory cannot have scripts.", inputPath, targetLocation.Node.Path));

View File

@@ -16,8 +16,6 @@ namespace FlaxEditor.Modules
/// <seealso cref="FlaxEditor.Modules.EditorModule" /> /// <seealso cref="FlaxEditor.Modules.EditorModule" />
public sealed class SceneEditingModule : EditorModule public sealed class SceneEditingModule : EditorModule
{ {
private int _lastSelectionStatus = 0;
/// <summary> /// <summary>
/// The selected objects. /// The selected objects.
/// </summary> /// </summary>
@@ -195,20 +193,6 @@ namespace FlaxEditor.Modules
Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo)); Undo.AddAction(new SelectionChangeAction(before, Selection.ToArray(), OnSelectionUndo));
OnSelectionChanged(); OnSelectionChanged();
// Display amount of selected actors on the status bar
Editor.UI.RemoveStatusMessage(_lastSelectionStatus);
var objects = Selection.Count;
var actors = CountActors(Selection);
_lastSelectionStatus = Editor.UI.AddStatusMessage($"Selected {objects} {(objects > 1 ? "objects" : "object")} (total {actors} {(actors > 1 ? "actors" : "actor")})");
}
private int CountActors(List<SceneGraphNode> nodes)
{
int result = 0;
foreach (var node in nodes)
result += 1 + CountActors(node.ChildNodes);
return result;
} }
private void OnSelectionUndo(SceneGraphNode[] toSelect) private void OnSelectionUndo(SceneGraphNode[] toSelect)
@@ -245,7 +229,7 @@ namespace FlaxEditor.Modules
if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && node.AffectsNavigationWithChildren) if (!isPlayMode && options.General.AutoRebuildNavMesh && actor.Scene && node.AffectsNavigationWithChildren)
{ {
var bounds = actor.BoxWithChildren; var bounds = actor.BoxWithChildren;
Navigation.BuildNavMesh(bounds, options.General.AutoRebuildNavMeshTimeoutMs); Navigation.BuildNavMesh(actor.Scene, bounds, options.General.AutoRebuildNavMeshTimeoutMs);
} }
} }

View File

@@ -267,7 +267,7 @@ namespace FlaxEditor.Modules
} }
/// <inheritdoc /> /// <inheritdoc />
public override void OnPlayBeginning() public override void OnPlayBegin()
{ {
Editor.Windows.FlashMainWindow(); Editor.Windows.FlashMainWindow();

View File

@@ -16,6 +16,7 @@ using FlaxEditor.Windows;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json; using FlaxEngine.Json;
using DockHintWindow = FlaxEditor.GUI.Docking.DockHintWindow;
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel; using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
using FlaxEditor.Content.Settings; using FlaxEditor.Content.Settings;
using FlaxEditor.Options; using FlaxEditor.Options;
@@ -28,52 +29,10 @@ namespace FlaxEditor.Modules
/// <seealso cref="FlaxEditor.Modules.EditorModule" /> /// <seealso cref="FlaxEditor.Modules.EditorModule" />
public sealed class UIModule : EditorModule public sealed class UIModule : EditorModule
{ {
private class MainWindowDecorations : WindowDecorations
{
public MainWindowDecorations(RootControl window, bool iconOnly)
: base(window, iconOnly)
{
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (base.OnKeyDown(key))
return true;
// Fallback to the edit window for shortcuts
var editor = Editor.Instance;
return editor.Windows.EditWin.InputActions.Process(editor, this, key);
}
/// <inheritdoc />
public override void DrawBorders()
{
// Draw main window borders if using a custom style
var win = RootWindow.Window;
if (win.IsMaximized)
return;
var color = Editor.Instance.UI.StatusBar.StatusColor;
var rect = new Rectangle(0.5f, 0.5f, Parent.Width - 1.0f, Parent.Height - 1.0f - StatusBar.DefaultHeight);
Render2D.DrawLine(rect.UpperLeft, rect.UpperRight, color);
Render2D.DrawLine(rect.UpperLeft, rect.BottomLeft, color);
Render2D.DrawLine(rect.UpperRight, rect.BottomRight, color);
}
}
private struct Status
{
public int ID;
public string Text;
public DateTime EndTime;
}
private Label _progressLabel; private Label _progressLabel;
private ProgressBar _progressBar; private ProgressBar _progressBar;
private Button _outputLogButton; private Button _outputLogButton;
private List<Status> _statusMessages; private List<KeyValuePair<string, DateTime>> _statusMessages;
private int _statusID = 1;
private ContentStats _contentStats; private ContentStats _contentStats;
private bool _progressFailed; private bool _progressFailed;
@@ -166,7 +125,6 @@ namespace FlaxEditor.Modules
private ContextMenuButton _menuToolsProfilerWindow; private ContextMenuButton _menuToolsProfilerWindow;
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault; private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
private ContextMenuButton _menuToolsTakeScreenshot; private ContextMenuButton _menuToolsTakeScreenshot;
private ContextMenuButton _menuToolsOpenLocalFolder;
private ContextMenuChildMenu _menuWindowApplyWindowLayout; private ContextMenuChildMenu _menuWindowApplyWindowLayout;
private ToolStripButton _toolStripSaveAll; private ToolStripButton _toolStripSaveAll;
@@ -186,11 +144,6 @@ namespace FlaxEditor.Modules
/// </summary> /// </summary>
public MainMenu MainMenu; public MainMenu MainMenu;
/// <summary>
/// The window decorations (title bar with buttons)
/// </summary>
public WindowDecorations WindowDecorations;
/// <summary> /// <summary>
/// The tool strip control. /// The tool strip control.
/// </summary> /// </summary>
@@ -387,7 +340,7 @@ namespace FlaxEditor.Modules
string text; string text;
if (_statusMessages != null && _statusMessages.Count != 0) if (_statusMessages != null && _statusMessages.Count != 0)
text = _statusMessages[0].Text; text = _statusMessages[0].Key;
else if (Editor.StateMachine.CurrentState.Status != null) else if (Editor.StateMachine.CurrentState.Status != null)
text = Editor.StateMachine.CurrentState.Status; text = Editor.StateMachine.CurrentState.Status;
else if (contentStats.LoadingAssetsCount != 0) else if (contentStats.LoadingAssetsCount != 0)
@@ -409,34 +362,13 @@ namespace FlaxEditor.Modules
/// Adds the status bar message text to be displayed as a notification. /// Adds the status bar message text to be displayed as a notification.
/// </summary> /// </summary>
/// <param name="message">The message to display.</param> /// <param name="message">The message to display.</param>
/// <returns>The ID of that status message (unique). Can be used to hide it manually.</returns> public void AddStatusMessage(string message)
public int AddStatusMessage(string message)
{ {
if (_statusMessages == null) if (_statusMessages == null)
_statusMessages = new List<Status>(); _statusMessages = new List<KeyValuePair<string, DateTime>>();
var status = new Status { ID = _statusID++, Text = message, EndTime = DateTime.Now + TimeSpan.FromSeconds(3.0f) }; _statusMessages.Add(new KeyValuePair<string, DateTime>(message, DateTime.Now + TimeSpan.FromSeconds(3.0f)));
_statusMessages.Add(status);
if (_statusMessages.Count == 1) if (_statusMessages.Count == 1)
UpdateStatusBar(); UpdateStatusBar();
return status.ID;
}
/// <summary>
/// Removes a specific status message once it's not needed anymore,
/// </summary>
/// <param name="id">The ID of the message returned by <see cref="AddStatusMessage"/>.</param>
public void RemoveStatusMessage(int id)
{
if (_statusMessages == null || id == 0)
return;
for (var i = 0; i < _statusMessages.Count; i++)
{
if (_statusMessages[i].ID == id)
{
_statusMessages.RemoveAt(i);
return;
}
}
} }
internal bool ProgressVisible internal bool ProgressVisible
@@ -494,11 +426,19 @@ namespace FlaxEditor.Modules
InitToolstrip(mainWindow); InitToolstrip(mainWindow);
InitStatusBar(mainWindow); InitStatusBar(mainWindow);
InitDockPanel(mainWindow); InitDockPanel(mainWindow);
InitWindowDecorations(mainWindow);
Editor.Options.OptionsChanged += OnOptionsChanged; Editor.Options.OptionsChanged += OnOptionsChanged;
mainWindow.PerformLayout(true); // Add dummy control for drawing the main window borders if using a custom style
#if PLATFORM_WINDOWS
if (!Editor.Options.Options.Interface.UseNativeWindowSystem)
#endif
{
mainWindow.AddChild(new CustomWindowBorderControl
{
Size = Float2.Zero,
});
}
} }
private void InitViewportScaleOptions() private void InitViewportScaleOptions()
@@ -549,13 +489,13 @@ namespace FlaxEditor.Modules
public void SaveCustomViewportScalingOptions() public void SaveCustomViewportScalingOptions()
{ {
var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions); var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions);
Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions); Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions);
} }
/// <inheritdoc /> /// <inheritdoc />
public override void OnUpdate() public override void OnUpdate()
{ {
if (_statusMessages != null && _statusMessages.Count > 0 && _statusMessages[0].EndTime - DateTime.Now < TimeSpan.Zero) if (_statusMessages != null && _statusMessages.Count > 0 && _statusMessages[0].Value - DateTime.Now < TimeSpan.Zero)
{ {
_statusMessages.RemoveAt(0); _statusMessages.RemoveAt(0);
UpdateStatusBar(); UpdateStatusBar();
@@ -570,6 +510,23 @@ namespace FlaxEditor.Modules
} }
} }
private class CustomWindowBorderControl : Control
{
/// <inheritdoc />
public override void Draw()
{
var win = RootWindow.Window;
if (win.IsMaximized)
return;
var color = Editor.Instance.UI.StatusBar.StatusColor;
var rect = new Rectangle(0.5f, 0.5f, Parent.Width - 1.0f, Parent.Height - 1.0f - StatusBar.DefaultHeight);
Render2D.DrawLine(rect.UpperLeft, rect.UpperRight, color);
Render2D.DrawLine(rect.UpperLeft, rect.BottomLeft, color);
Render2D.DrawLine(rect.UpperRight, rect.BottomRight, color);
}
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnEndInit() public override void OnEndInit()
{ {
@@ -601,6 +558,13 @@ namespace FlaxEditor.Modules
UpdateToolstrip(); 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) private IColorPickerDialog ShowPickColorDialog(Control targetControl, Color initialValue, ColorValueBox.ColorPickerEvent colorChanged, ColorValueBox.ColorPickerClosedEvent pickerClosed, bool useDynamicEditing)
{ {
var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing); var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing);
@@ -654,12 +618,10 @@ namespace FlaxEditor.Modules
private void InitMainMenu(RootControl mainWindow) private void InitMainMenu(RootControl mainWindow)
{ {
MainMenu = new MainMenu() MainMenu = new MainMenu(mainWindow)
{ {
Parent = mainWindow Parent = mainWindow
}; };
if (Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
MainMenu.Height = 28;
var inputOptions = Editor.Options.Options.Input; var inputOptions = Editor.Options.Options.Input;
@@ -763,22 +725,12 @@ namespace FlaxEditor.Modules
_menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot); _menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
cm.AddSeparator(); cm.AddSeparator();
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show()); cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
cm.AddSeparator();
var childMenu = cm.AddChildMenu("Open Product Local folder");
childMenu.ContextMenu.AddButton("Editor", () => FileSystem.ShowFileExplorer(Globals.ProductLocalFolder));
_menuToolsOpenLocalFolder = childMenu.ContextMenu.AddButton("Game", () =>
{
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
GameSettings settings = GameSettings.Load<GameSettings>();
string path = Path.Combine(localAppData, settings.CompanyName, settings.ProductName);
FileSystem.ShowFileExplorer(path);
});
// Window // Window
MenuWindow = MainMenu.AddButton("Window"); MenuWindow = MainMenu.AddButton("Window");
cm = MenuWindow.ContextMenu; cm = MenuWindow.ContextMenu;
cm.VisibleChanged += OnMenuWindowVisibleChanged; cm.VisibleChanged += OnMenuWindowVisibleChanged;
cm.AddButton("Content", inputOptions.ContentWindow, Editor.Windows.ContentWin.FocusOrShow); cm.AddButton("Content", inputOptions.ContentWindow,Editor.Windows.ContentWin.FocusOrShow);
cm.AddButton("Scene", inputOptions.SceneWindow, Editor.Windows.SceneWin.FocusOrShow); cm.AddButton("Scene", inputOptions.SceneWindow, Editor.Windows.SceneWin.FocusOrShow);
cm.AddButton("Toolbox", inputOptions.ToolboxWindow, Editor.Windows.ToolboxWin.FocusOrShow); cm.AddButton("Toolbox", inputOptions.ToolboxWindow, Editor.Windows.ToolboxWin.FocusOrShow);
cm.AddButton("Properties", inputOptions.PropertiesWindow, Editor.Windows.PropertiesWin.FocusOrShow); cm.AddButton("Properties", inputOptions.PropertiesWindow, Editor.Windows.PropertiesWin.FocusOrShow);
@@ -811,23 +763,6 @@ namespace FlaxEditor.Modules
cm.AddButton("Information about Flax", () => new AboutDialog().Show()); cm.AddButton("Information about Flax", () => new AboutDialog().Show());
} }
private void InitWindowDecorations(RootControl mainWindow)
{
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
string driver = string.Empty;
#if PLATFORM_LINUX
driver = LinuxPlatform.DisplayServer;
if (!string.IsNullOrEmpty(driver))
driver = $" ({driver})";
#endif
WindowDecorations = new MainWindowDecorations(mainWindow, !Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
{
Parent = mainWindow,
IconTooltipText = $"{mainWindow.RootWindow.Title}\nVersion {Globals.EngineVersion}\nConfiguration {configuration}\nGraphics {GPUDevice.Instance.RendererType}{driver}",
};
}
private void OnOptionsChanged(EditorOptions options) private void OnOptionsChanged(EditorOptions options)
{ {
var inputOptions = options.Input; var inputOptions = options.Input;
@@ -1127,10 +1062,6 @@ namespace FlaxEditor.Modules
_menuToolsBuildNavMesh.Enabled = canEdit; _menuToolsBuildNavMesh.Enabled = canEdit;
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning; _menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
_menuToolsSetTheCurrentSceneViewAsDefault.Enabled = Level.ScenesCount > 0; _menuToolsSetTheCurrentSceneViewAsDefault.Enabled = Level.ScenesCount > 0;
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
GameSettings settings = GameSettings.Load<GameSettings>();
string path = Path.Combine(localAppData, settings.CompanyName, settings.ProductName);
_menuToolsOpenLocalFolder.Enabled = Directory.Exists(path);
c.PerformLayout(); c.PerformLayout();
} }
@@ -1252,7 +1183,6 @@ namespace FlaxEditor.Modules
{ {
// Clear UI references (GUI cannot be used after window closing) // Clear UI references (GUI cannot be used after window closing)
MainMenu = null; MainMenu = null;
WindowDecorations = null;
ToolStrip = null; ToolStrip = null;
MasterPanel = null; MasterPanel = null;
StatusBar = null; StatusBar = null;

View File

@@ -10,6 +10,7 @@ using System.Text;
using System.Xml; using System.Xml;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.GUI.Dialogs; using FlaxEditor.GUI.Dialogs;
using FlaxEditor.GUI.Docking;
using FlaxEditor.Windows; using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEditor.Windows.Profiler; using FlaxEditor.Windows.Profiler;
@@ -490,15 +491,10 @@ namespace FlaxEditor.Modules
Editor.LogWarning("Empty panel inside layout."); Editor.LogWarning("Empty panel inside layout.");
p.RemoveIt(); p.RemoveIt();
} }
else
{
p.CollapseEmptyTabsProxy();
}
} }
} }
panel.SelectTab(selectedTab); panel.SelectTab(selectedTab);
panel.CollapseEmptyTabsProxy();
} }
private static void SaveBounds(XmlWriter writer, Window win) private static void SaveBounds(XmlWriter writer, Window win)
@@ -762,19 +758,17 @@ namespace FlaxEditor.Modules
var settings = CreateWindowSettings.Default; var settings = CreateWindowSettings.Default;
settings.Title = "Flax Editor"; settings.Title = "Flax Editor";
settings.Size = Platform.DesktopSize * 0.75f; settings.Size = Platform.DesktopSize * 0.75f;
settings.MinimumSize = new Float2(200, 150);
settings.StartPosition = WindowStartPosition.CenterScreen; settings.StartPosition = WindowStartPosition.CenterScreen;
settings.ShowAfterFirstPaint = true; settings.ShowAfterFirstPaint = true;
#if PLATFORM_WINDOWS
if (Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true)) if (!Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
{ {
settings.HasBorder = false; settings.HasBorder = false;
#if PLATFORM_WINDOWS && !PLATFORM_SDL
// Skip OS sizing frame and implement it using LeftButtonHit // Skip OS sizing frame and implement it using LeftButtonHit
settings.HasSizingFrame = false; settings.HasSizingFrame = false;
#endif
} }
#if PLATFORM_LINUX && !PLATFORM_SDL #elif PLATFORM_LINUX
settings.HasBorder = false; settings.HasBorder = false;
#endif #endif
MainWindow = Platform.CreateWindow(ref settings); MainWindow = Platform.CreateWindow(ref settings);

View File

@@ -387,14 +387,6 @@ namespace FlaxEditor.Options
[EditorDisplay("Viewport"), EditorOrder(1760)] [EditorDisplay("Viewport"), EditorOrder(1760)]
public InputBinding ToggleOrthographic = new InputBinding(KeyboardKeys.NumpadDecimal); public InputBinding ToggleOrthographic = new InputBinding(KeyboardKeys.NumpadDecimal);
[DefaultValue(typeof(InputBinding), "G")]
[EditorDisplay("Viewport"), EditorOrder(1770)]
public InputBinding ToggleGameView = new InputBinding(KeyboardKeys.G);
[DefaultValue(typeof(InputBinding), "P")]
[EditorDisplay("Viewport"), EditorOrder(1770)]
public InputBinding ToggleNavMeshVisibility = new InputBinding(KeyboardKeys.P);
#endregion #endregion
#region Debug Views #region Debug Views
@@ -579,10 +571,6 @@ namespace FlaxEditor.Options
[EditorDisplay("View Flags"), EditorOrder(3260)] [EditorDisplay("View Flags"), EditorOrder(3260)]
public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift); public InputBinding DebugDraw = new InputBinding(KeyboardKeys.Alpha4, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("View Flags"), EditorOrder(3270)]
public InputBinding Particles = new InputBinding(KeyboardKeys.None);
#endregion #endregion
#region Interface #region Interface

View File

@@ -85,12 +85,10 @@ namespace FlaxEditor.Options
/// Never show the close button. /// Never show the close button.
/// </summary> /// </summary>
Never, Never,
/// <summary> /// <summary>
/// Show the close button on tabs that are currently selected. /// Show the close button on tabs that are currently selected.
/// </summary> /// </summary>
SelectedTab, SelectedTab,
/// <summary> /// <summary>
/// Show the close button on all tabs that can be closed. /// Show the close button on all tabs that can be closed.
/// </summary> /// </summary>
@@ -181,34 +179,6 @@ namespace FlaxEditor.Options
GameWindowThenRestore, GameWindowThenRestore,
} }
/// <summary>
/// Options for type of window decorations to use.
/// </summary>
public enum WindowDecorationsType
{
/// <summary>
/// Determined automatically based on the system and any known compatibility issues with native decorations.
/// </summary>
Auto,
/// <summary>
/// Automatically choose most compatible window decorations for child windows, prefer custom decorations on main window.
/// </summary>
[EditorDisplay(Name = "Auto (Child Only)")]
AutoChildOnly,
/// <summary>
/// Use native system window decorations on all windows.
/// </summary>
Native,
/// <summary>
/// Use custom client-side window decorations on all windows.
/// </summary>
[EditorDisplay(Name = "Client-side")]
ClientSide,
}
/// <summary> /// <summary>
/// Gets or sets the 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. /// Gets or sets the 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.
/// </summary> /// </summary>
@@ -298,14 +268,7 @@ namespace FlaxEditor.Options
[EditorDisplay("Interface"), EditorOrder(322)] [EditorDisplay("Interface"), EditorOrder(322)]
public bool ScrollToScriptOnAdd { get; set; } = true; public bool ScrollToScriptOnAdd { get; set; } = true;
#if PLATFORM_SDL #if PLATFORM_WINDOWS
/// <summary>
/// Gets or sets a value indicating whether use native window title bar decorations in child windows. Editor restart required.
/// </summary>
[DefaultValue(WindowDecorationsType.AutoChildOnly)]
[EditorDisplay("Interface"), EditorOrder(70), Tooltip("Determines whether use native window title bar decorations. Editor restart required.")]
public WindowDecorationsType WindowDecorations { get; set; } = WindowDecorationsType.AutoChildOnly;
#elif PLATFORM_WINDOWS
/// <summary> /// <summary>
/// Gets or sets a value indicating whether use native window title bar. Editor restart required. /// Gets or sets a value indicating whether use native window title bar. Editor restart required.
/// </summary> /// </summary>
@@ -314,7 +277,7 @@ namespace FlaxEditor.Options
public bool UseNativeWindowSystem { get; set; } = false; public bool UseNativeWindowSystem { get; set; } = false;
#endif #endif
#if PLATFORM_SDL || PLATFORM_WINDOWS #if PLATFORM_WINDOWS
/// <summary> /// <summary>
/// Gets or sets a value indicating whether a window containing a single tabs hides the tab bar. Editor restart recommended. /// Gets or sets a value indicating whether a window containing a single tabs hides the tab bar. Editor restart recommended.
/// </summary> /// </summary>
@@ -324,7 +287,7 @@ namespace FlaxEditor.Options
#endif #endif
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the minimum tab width should be used. Editor restart required. /// Gets or sets a value indicating wether the minum tab width should be used. Editor restart required.
/// </summary> /// </summary>
[DefaultValue(false)] [DefaultValue(false)]
[EditorDisplay("Tabs & Windows"), EditorOrder(99)] [EditorDisplay("Tabs & Windows"), EditorOrder(99)]
@@ -535,7 +498,7 @@ namespace FlaxEditor.Options
public float ConnectionCurvature { get; set; } = 1.0f; public float ConnectionCurvature { get; set; } = 1.0f;
/// <summary> /// <summary>
/// Gets or sets a value that indicates whether the context menu description panel is shown or not. /// Gets or sets a value that indicates wether the context menu description panel is shown or not.
/// </summary> /// </summary>
[DefaultValue(true)] [DefaultValue(true)]
[EditorDisplay("Visject"), EditorOrder(550), Tooltip("Shows/hides the description panel in visual scripting context menu.")] [EditorDisplay("Visject"), EditorOrder(550), Tooltip("Shows/hides the description panel in visual scripting context menu.")]

Some files were not shown because too many files have changed in this diff Show More