213 Commits
sdl_wip ... wip

Author SHA1 Message Date
a45aa74aca Revert "Build Editor bindings only when generating editor project files"
This reverts commit 55ad5ae367.
2025-03-18 01:16:53 +02:00
dbf5dd9e92 _sdl binary 2025-03-07 16:45:33 +02:00
b0ae2b4cd2 Update SDL3 to 3.2.6 2025-03-07 16:45:28 +02:00
ed8001ff8b Fix missing NETX_0_OR_GREATER definitions for previous versions 2025-02-26 22:37:18 +02:00
6e2ed2bdbd Fix TypeDescriptor hack for latest runtime versions 2025-02-26 22:07:29 +02:00
ba88bf8b0f Merge branch 'unload_alc_fix' into wip
# Conflicts:
#	Source/Editor/Modules/WindowsModule.cs
2025-02-26 20:31:07 +02:00
Wojtek Figat
56b2c96b3b Fix missing content database load when opening project without code compilation
#2469
2025-02-26 20:29:44 +02:00
Wojtek Figat
5c06d413b0 Add code sharing
#2469
2025-02-26 20:29:36 +02:00
1c17b77d1e Refocus editor after restoring windows 2025-02-26 20:29:23 +02:00
e24bb71e91 Fix stack overflow when restoring tab in floating window 2025-02-26 20:29:22 +02:00
3382aabefe Close and restore AssetEditorWindows on scripting reload 2025-02-26 20:29:22 +02:00
4ddc765ee4 Fix ContentDatabase not being loaded at the end of editor initialization 2025-02-26 20:29:21 +02:00
5fd64ead62 Fix custom content and importers blocking scripting reload 2025-02-26 20:29:21 +02:00
30257929e5 Fix error when ContentDatabase gets rebuilt while initializing editor 2025-02-26 20:29:21 +02:00
980a112c57 Clear VisjectSurface node caches and context menus during scripts reload 2025-02-26 20:29:20 +02:00
98bbcbd442 Close and restore Prefab windows during scripting reload 2025-02-26 20:29:20 +02:00
9f8faf4f17 Clear references holding on to types in game assemblies 2025-02-26 20:29:19 +02:00
691b9458ec Fix wrong prefab event unregistration 2025-02-26 20:29:19 +02:00
b095acd4a5 Fix scripting AssemblyLoadContext not getting unloaded 2025-02-26 20:29:19 +02:00
afbb8225d8 Avoid showing tooltips in inactive windows 2025-02-26 20:09:32 +02:00
35678b06a8 Merge branch 'api_macro_consistency' into signalgame2 2025-02-26 20:09:31 +02:00
96d39ecb30 _xaudio2 2025-02-26 20:09:31 +02:00
2c7b11a691 Remove texturereferences in default materials 2025-02-26 20:09:30 +02:00
83c288d739 Disable LFS override 2025-02-26 20:09:30 +02:00
8c6b853ee5 Update to enet 2.3.6 2025-02-26 20:09:29 +02:00
b414d7d026 Merge branch 'fixed_update_deltatime' into signalgame2 2025-02-26 20:09:28 +02:00
ae6ec809b8 Merge branch 'richtextbox_optimize' into signalgame2 2025-02-26 20:09:28 +02:00
f47214ae0a Merge branch 'unload_alc_fix' into signalgame2 2025-02-26 20:09:27 +02:00
bddd1b0984 Merge branch 'sdl_platform' into signalgame2 2025-02-26 20:09:27 +02:00
e2e77385b1 Fix missing semicolons 2025-02-26 20:09:26 +02:00
f4c13032a2 Require semicolon after most engine API macros
# Conflicts:
#	Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp
2025-02-26 20:09:26 +02:00
43801d0824 Always run fixed update ticks at fixed deltatime
The random variance in fixed updates makes it impossible to do anything deterministic during physics ticks.
2025-02-26 20:09:25 +02:00
16cd027bf3 Optimize RichTextBox rendering with long text 2025-02-26 20:09:25 +02:00
f361c4bbdb Refocus editor after restoring windows 2025-02-26 20:09:24 +02:00
c4f5777536 Fix stack overflow when restoring tab in floating window 2025-02-26 20:09:24 +02:00
c740d27b0e Close and restore AssetEditorWindows on scripting reload 2025-02-26 20:09:23 +02:00
800b163de9 Fix ContentDatabase not being loaded at the end of editor initialization 2025-02-26 20:09:22 +02:00
7f317d0fb6 Fix custom content and importers blocking scripting reload 2025-02-26 20:09:22 +02:00
714cdd84ad Fix error when ContentDatabase gets rebuilt while initializing editor 2025-02-26 20:09:22 +02:00
26b5172aea Clear VisjectSurface node caches and context menus during scripts reload 2025-02-26 20:09:21 +02:00
47b95f5650 Close and restore Prefab windows during scripting reload 2025-02-26 20:09:21 +02:00
989a5441f3 Clear references holding on to types in game assemblies 2025-02-26 20:09:20 +02:00
6394a7aae0 Fix wrong prefab event unregistration 2025-02-26 20:09:19 +02:00
beff9d5241 Fix scripting AssemblyLoadContext not getting unloaded 2025-02-26 20:09:19 +02:00
Wojtek Figat
83c3201ef8 Fix regression in rapidjson update 2025-02-25 18:09:47 +01:00
Wojtek Figat
dcba97f84a Fix missing masked terrain rendering
#3177
2025-02-25 16:46:17 +01:00
Wojtek Figat
ca6544204b Fix actor hierarchy initialization when it gets modified by a script on the fly
#2940 #2623 #2751
2025-02-25 15:32:20 +01:00
Wojtek Figat
1c3d1b623d Optimize and cleanup some actor code 2025-02-25 15:31:46 +01:00
Wojtek Figat
bf21b0a267 Fix collision cooking for skinned models that use different vertex format
#3246
2025-02-24 22:05:33 +01:00
Wojtek Figat
afc4158dd3 Fix sprite and texture 9-slice rendering brush to properly calculate border size 2025-02-24 14:19:51 +01:00
Wojtek Figat
09ead0cc7a Fix Eye Adaptation in colllision data window viewport 2025-02-24 12:30:44 +01:00
Wojtek Figat
f2e840577a Merge branch 'Tryibion-prefab-doubleclick-obj-ref' 2025-02-24 00:10:11 +01:00
Wojtek Figat
345cbdb8d4 Merge branch 'prefab-doubleclick-obj-ref' of https://github.com/Tryibion/FlaxEngine into Tryibion-prefab-doubleclick-obj-ref 2025-02-24 00:10:04 +01:00
Wojtek Figat
0ebda18669 Fix game-build version of DebugDraw for C# but without xml docs
#3201
2025-02-24 00:09:52 +01:00
Wojtek Figat
efa081716f Merge branch 'Tryibion-tube-to-capsule' 2025-02-24 00:00:30 +01:00
Wojtek Figat
7225737984 Merge branch 'tube-to-capsule' of https://github.com/Tryibion/FlaxEngine into Tryibion-tube-to-capsule 2025-02-23 23:58:28 +01:00
Wojtek Figat
0b1a64305a Merge branch 'GoaLitiuM-update_rapidjson' 2025-02-23 23:51:12 +01:00
Wojtek Figat
bfd972b96d Add SIMD support for rapidjson when processing json data
#3155
2025-02-23 23:38:07 +01:00
Wojtek Figat
25f26a7a91 Merge branch 'update_rapidjson' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-update_rapidjson 2025-02-23 23:26:55 +01:00
Wojtek Figat
d9ae41ed10 Fix editor transform gizmos rendering to draw over other editor shapes
#2954
2025-02-23 23:01:20 +01:00
Wojtek Figat
68877eebe3 Format code 2025-02-23 21:31:30 +01:00
Wojtek Figat
5ed18c7448 Fix fc4b79239b 2025-02-23 21:28:02 +01:00
Wojtek Figat
1fda1d749d Merge branch 'GoaLitiuM-launchsettings_fix' 2025-02-23 21:24:31 +01:00
Wojtek Figat
ac728f1a31 Merge branch 'launchsettings_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-launchsettings_fix 2025-02-23 21:24:17 +01:00
Wojtek Figat
8beeea0da1 Merge branch 'davevanegdom-Double-Click-Scene-Node-Actions' 2025-02-23 21:23:18 +01:00
Wojtek Figat
fc4b79239b Refactor new scene tree double click feature to support both prefab and scene editing
#1502
2025-02-23 21:23:09 +01:00
Wojtek Figat
618027b181 Merge branch 'Double-Click-Scene-Node-Actions' of https://github.com/davevanegdom/FlaxEngine into davevanegdom-Double-Click-Scene-Node-Actions
# Conflicts:
#	Source/Editor/Modules/PrefabsModule.cs
#	Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
2025-02-23 21:18:38 +01:00
Wojtek Figat
f97ead8a20 Merge branch 'davevanegdom-DebugOutputImprovements' 2025-02-23 20:30:01 +01:00
Wojtek Figat
bae381430a Cleanup code
#1437
2025-02-23 20:29:58 +01:00
Wojtek Figat
1c3f7fcec0 Merge branch 'DebugOutputImprovements' of https://github.com/davevanegdom/FlaxEngine into davevanegdom-DebugOutputImprovements
# Conflicts:
#	Source/Editor/Options/InterfaceOptions.cs
#	Source/Editor/Windows/DebugLogWindow.cs
2025-02-23 20:29:10 +01:00
Chandler Cox
65a219512c Add double clicking an object reference in a prefab to select the actor within the prefab. 2025-02-21 15:52:43 -06:00
Wojtek Figat
bb12562c2f Fix crash when setting C# property of value-type from native code 2025-02-21 20:22:54 +01:00
Wojtek Figat
b81b0b7616 Fix text clipping behind the button in Behavior Knowledge Selector editor 2025-02-21 19:34:35 +01:00
Wojtek Figat
bd9a5f03a4 Fix crash when importing fbx model with convex polygon with duplicated vertices
#3222
2025-02-21 17:36:20 +01:00
Wojtek Figat
9d5d80bf4a Fix crash when using physics overlap tests with Collider outputs that catch Terrain
#3221
2025-02-21 15:07:44 +01:00
Wojtek Figat
44e894f406 Remove unused default value codegen 2025-02-21 15:07:09 +01:00
Wojtek Figat
366b47ad80 Fix crash when applying prefab with missing scripts in use
#3239
2025-02-20 23:50:36 +01:00
Wojtek Figat
b3508b9fe1 Fix Visject gradient stops to update graph only on sliding end
#3226
2025-02-20 20:28:46 +01:00
Wojtek Figat
3f2eab5206 Optimize divide into multiply 2025-02-20 17:04:20 +01:00
Wojtek Figat
5bdf5da142 Resave engine materials
#3231
2025-02-20 10:09:37 +01:00
c823257b79 Fix invalid paths in C# launch settings on Windows 2025-02-19 17:23:47 +02:00
Wojtek Figat
937d369856 Fix crash in particles system when assets gets loading/unloaded while async jobs are active 2025-02-18 23:27:49 +01:00
Wojtek Figat
060bc0aaf8 Fix crash in animations system when assets gets loading/unloaded while async jobs are active
#2974
2025-02-18 22:30:49 +01:00
Wojtek Figat
c81ddd09cc Fix spatial audio bug regression from 84843f8cbb
#3224 #3206
2025-02-17 23:55:26 +01:00
Wojtek Figat
015c4ab475 Fix memory leak in particle buffers recycling
#3152
2025-02-17 23:25:40 +01:00
Wojtek Figat
ccdf004404 Fix memory leak in Video player on Windows
#3158
2025-02-17 21:19:45 +01:00
Wojtek Figat
9049093267 Fix scene object reference serialization in C# scripts
#3136
2025-02-17 11:57:31 +01:00
Wojtek Figat
9d4d9ccf38 Optimize compilation on MSVC as it can ommit include 2025-02-17 10:24:04 +01:00
Wojtek Figat
8b1d678f2e Fix scene object reference serialization in Visual Script properties
#3136
2025-02-17 10:23:07 +01:00
Wojtek Figat
67db774a2f Fix compilation regression 2025-02-17 00:27:06 +01:00
Wojtek Figat
3cd951f0a0 Merge branch 'Tryibion-add-context-to-obj-ref-editor' 2025-02-16 21:15:48 +01:00
Wojtek Figat
0525ce2cb3 Merge branch 'add-context-to-obj-ref-editor' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-context-to-obj-ref-editor 2025-02-16 20:42:23 +01:00
Wojtek Figat
5e74ec01ce Merge branch 'Tryibion-prefab-ui-mode' 2025-02-16 20:38:03 +01:00
Wojtek Figat
bbbc0c9d50 Merge branch 'prefab-ui-mode' of https://github.com/Tryibion/FlaxEngine into Tryibion-prefab-ui-mode 2025-02-16 20:35:00 +01:00
Wojtek Figat
25067959eb Add nested prefabs editing buttons inside Prefab Window
#1595
2025-02-16 20:34:33 +01:00
Wojtek Figat
086ddc96bb Fix incorrect prefab serialization to correctly handle diff on object references to prefab objects
#3136
2025-02-14 17:07:33 +01:00
Wojtek Figat
3394de0b93 Fix grid in multi-blend node to draw behind the lines
#3212
2025-02-13 23:29:02 +01:00
16be2fc857 Update SDL3 to 3.2.4 2025-02-13 18:05:09 +02:00
Wojtek Figat
abd0c7dece Add support for displaying Multiple Values info to object reference pickers
#2984
2025-02-12 22:31:53 +01:00
Wojtek Figat
ee540b3cb7 Speculative fix for error in thumbnails rendering 2025-02-12 22:13:29 +01:00
Wojtek Figat
c146e156ec Fix perlin and simplex noises to return normalized value to range 0-1
#3154
2025-02-12 22:13:09 +01:00
Wojtek Figat
6efb015169 Merge code for Perlin Noise impl 2025-02-12 17:21:13 +01:00
Wojtek Figat
a982e0a111 Fix crash when reading object value from BehaviorKnowledgeSelector
#3171
2025-02-12 16:54:33 +01:00
Wojtek Figat
84843f8cbb Fix playing mono audio sounds with panning
Tested on OpenAL and XAudio backkend on Windows.

#3206
2025-02-11 23:35:08 +01:00
Wojtek Figat
dccb43702e Add missing casting from Double to Float vectors within Variant 2025-02-11 14:51:17 +01:00
Wojtek Figat
f459249f78 Fix compilation regression from aa8add7b38 2025-02-11 14:23:10 +01:00
Wojtek Figat
3ad369501a Add support for searching actors and scripts by interface
#3199
2025-02-11 14:22:44 +01:00
Wojtek Figat
b0fe4373b0 Merge branch 'xxSeys1-AudioSliderGamePanelFix' 2025-02-11 14:07:16 +01:00
Wojtek Figat
9df5ed5b7f Merge branch 'AudioSliderGamePanelFix' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-AudioSliderGamePanelFix 2025-02-11 14:07:09 +01:00
Wojtek Figat
aa8add7b38 Fix large worlds rendering of meshes
Add `Double4x4` for higher precision matrices operations

#2985
2025-02-11 13:01:48 +01:00
Wojtek Figat
21f8dab5de Tweak 58090aa6d6 to secure for incorrect includes and usage 2025-02-11 00:33:08 +01:00
Wojtek Figat
4baa38c0cc Add explicit cast to in vector in C# api 2025-02-11 00:32:20 +01:00
Wojtek Figat
3c091dc214 Fix editor grid gizmo when using Large Worlds 2025-02-11 00:32:04 +01:00
Wojtek Figat
58090aa6d6 Fix triplanar texture mapping when using Large Worlds
#3001
2025-02-11 00:31:37 +01:00
Chandler Cox
2521ed4ad5 Change DrawTube to DrawCapsule. Depricate old Tube code. 2025-02-08 21:15:49 -06:00
xxSeys1
6a5f22400d update volume slider in game panel on menu show 2025-02-05 12:35:49 +01:00
Wojtek Figat
a5fffc0c9e Fix DebugDraw.DrawWireArc with Large Worlds enabled
#3049
2025-02-04 23:44:31 +01:00
Wojtek Figat
e551ecbe5f Fix build warning with Large Worlds enabled 2025-02-04 23:44:12 +01:00
561239a4b2 Fix window dragging when not supported by Wayland compositor
(cherry picked from commit 3554747a67)
2025-02-02 18:38:06 +02:00
389b2e6148 Show current display server in Editor window tooltip
(cherry picked from commit 62968dd437)
2025-02-02 18:38:06 +02:00
9403b87788 Properly mark floating windows with transparency support
(cherry picked from commit c660fac524)
2025-02-02 18:38:06 +02:00
64cceac913 Enable transparency support in Vulkan swapchains
(cherry picked from commit 431a69e357)
2025-02-02 18:38:06 +02:00
c523079f0e Fix compilation for game builds
(cherry picked from commit f4fcc07288)
2025-02-02 18:38:06 +02:00
Wojtek Figat
8542f78b0b Merge branch 'xxSeys1-BetterRayNormAssert' 2025-02-01 15:26:25 +01:00
Wojtek Figat
da513972e8 Simplify message to be single-line with less text
#2990
2025-02-01 15:26:13 +01:00
Wojtek Figat
be293a957a Merge branch 'BetterRayNormAssert' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-BetterRayNormAssert 2025-02-01 15:24:44 +01:00
Wojtek Figat
8e26591c0b Merge branch 'xxSeys1-GamePanelAudio' 2025-02-01 15:23:39 +01:00
Wojtek Figat
4e31d436d5 Merge branch 'GamePanelAudio' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-GamePanelAudio 2025-02-01 15:23:33 +01:00
Wojtek Figat
b6f7914b14 Fix RenderToTextureControl to render correctly when using different texture size than control size
#2760
2025-02-01 15:17:21 +01:00
Wojtek Figat
9ffbe1f8ca Add support in scripting for using interfaces on structures
#2679
2025-01-31 23:36:15 +01:00
Wojtek Figat
4e0cd9e8a9 Add support for creating Json Assets in editor out of structure type
#2679
2025-01-31 21:58:36 +01:00
Wojtek Figat
24f3dfe264 Fix selected spline points to be drawn relative to the view for greater readability
#2595
2025-01-31 21:01:26 +01:00
Wojtek Figat
42fc62eb68 Add Actor.Clone for actors duplication at runtime (including scripts and children)
#2012
2025-01-31 10:21:05 +01:00
Wojtek Figat
b1392be3a1 Fix typo 2025-01-30 22:48:07 +01:00
Wojtek Figat
04dde7a3f2 Add warnings on incorrect GPUBuffer or GPUTexture usage when binding to GPUContext (in non-release builds) 2025-01-30 22:03:21 +01:00
Wojtek Figat
44fae3838e Add GPUResourceUsage.Staging for both CPU read/write access 2025-01-30 20:39:04 +01:00
Wojtek Figat
f11306af24 Add caching and restoring curve height in properties panel
#2455
2025-01-30 17:42:54 +01:00
Wojtek Figat
4057dc189d Fix SnapToGrid to skip when grid component is 0 2025-01-30 17:26:34 +01:00
Wojtek Figat
fc98b5f1f0 Add snapping to grid with Ctrl key when moving keyframes in curve
#2455
2025-01-30 17:26:04 +01:00
Wojtek Figat
4d6282a5b4 Add focus selection to curve editor and apply margin around shown curve section
#2455
2025-01-29 23:54:41 +01:00
Wojtek Figat
0e058b2590 Fix curve tangents reset on drag start
#2455
2025-01-28 23:18:26 +01:00
Wojtek Figat
a31279954a Fix curve editor scroll bars to be hidden when not enabled
#1083
2025-01-28 23:07:05 +01:00
Wojtek Figat
d25cb7a9da Fix curve tangent handles to maintain size relative to the current view scale
Fix curve tangent colors to match editor style
Fix curve tangents editing to have stable movement no matter the view scale

#2455
2025-01-28 22:59:39 +01:00
942124fdc3 Fix cloning SDL repository 2025-01-28 22:24:21 +02:00
9085874d4e Fix text input not working on X11 2025-01-28 22:10:46 +02:00
2f5562f8eb Fix button latching on Windows after drag and drop operation 2025-01-28 22:10:45 +02:00
6733e45729 Implement new window dragging system 2025-01-28 22:10:44 +02:00
37438afbf6 Fix mouse resetting issues after ending relative mode 2025-01-28 22:10:44 +02:00
7c34b1c855 Fix frame stutter when window is focused 2025-01-28 22:10:43 +02:00
3dc2e55627 Fix error when docking to sides of tabbed panel 2025-01-28 22:10:43 +02:00
c658dd72e7 Cleanup Linux SDL implementation 2025-01-28 22:10:43 +02:00
5b8c81dfac Support compiling third party library C files as C code 2025-01-28 22:10:42 +02:00
bf4ec5f91a Implement Wayland protocols module and file generation 2025-01-28 22:10:42 +02:00
15024b38b9 Fix mouse warping after ending relative mode 2025-01-28 22:10:42 +02:00
71ec415cc4 Add git fetch method for dependencies 2025-01-28 22:10:41 +02:00
81b6f47d8a Fix window ShowInTaskbar setting 2025-01-28 22:10:41 +02:00
e55fd18771 Fix various issues with child window positioning 2025-01-28 22:10:41 +02:00
fd97c2bdf2 Add Window.IsAlwaysOnTop property 2025-01-28 22:10:40 +02:00
6ca71a872d Use SDL locale 2025-01-28 22:10:40 +02:00
18e92425bb Allow window with single tab to be dragged from tab area 2025-01-28 22:10:40 +02:00
3feebe8910 Fix ValueBox mouse position resetting after releasing the button 2025-01-28 22:10:39 +02:00
9fc7fc7a2e Fix SDL build process on Linux 2025-01-28 22:10:39 +02:00
642d90a293 Update SDL to 3.2.0 2025-01-28 22:10:39 +02:00
f5313b9ffd Force cursor to center of Game Window when tab handle is clicked 2025-01-28 22:10:38 +02:00
Chandler Cox
7abed39473 Fix rotation using SDL 2025-01-28 22:10:38 +02:00
ffc40ba634 Fix Linux compilation without SDL 2025-01-28 22:09:14 +02:00
84f3cda190 Fix compilation 2025-01-28 22:09:14 +02:00
0f20f387fc Update SDL3 2025-01-28 22:09:13 +02:00
67093a0d28 Fix compilation issues 2025-01-28 22:09:13 +02:00
63eaf1adf2 Fix windows not being hidden initially 2025-01-28 22:09:13 +02:00
28d167b4f8 Fix parent window position handling with popup/tooltip windows 2025-01-28 22:09:12 +02:00
7bff09eeb9 Fix compilation errors in other platforms 2025-01-28 22:09:12 +02:00
5afde966ef Fix CI for Linux 2025-01-28 22:09:12 +02:00
5df1f32305 Prevent building with SDL in unsupported platforms 2025-01-28 22:09:11 +02:00
670f2ee2b0 Fallback to X11 message box implementation when SDL fails 2025-01-28 22:09:11 +02:00
5abf336696 Fix popup and context menus not working on Wayland 2025-01-28 22:09:11 +02:00
7ae0a65c0e Hide warnings for unsupported SDL operations on Wayland 2025-01-28 22:09:10 +02:00
9e88233957 Log a warning for not implemented Wayland functionality 2025-01-28 22:09:10 +02:00
d0a4213538 Fix compilation in Linux 2025-01-28 22:09:10 +02:00
b2467edc0f Enable warning sound in question dialogs 2025-01-28 22:09:09 +02:00
94e398a6b3 Enable modern Windows dialog boxes 2025-01-28 22:09:09 +02:00
e5ca67618f Implement relative mouse mode (raw input) for SDL platform 2025-01-28 22:09:09 +02:00
2da908d9b8 Add flag for Window types 2025-01-28 22:09:09 +02:00
34f187161c Enable native windowing system settings with SDL platform 2025-01-28 22:09:08 +02:00
0e5e0169bf Add command-line switches to force X11 and Wayland SDL drivers 2025-01-28 22:09:08 +02:00
f318d3aadc Implement SDL platform, windowing and input handling 2025-01-28 22:09:08 +02:00
43e38df8b0 Refactor application window class name 2025-01-28 22:09:07 +02:00
86b999f6a4 Move Window related enums to separate header file 2025-01-28 22:09:07 +02:00
553ca7d71c Refactor Windows drag and drop implementation 2025-01-28 22:09:06 +02:00
2594cc4546 Refactor ScreenUtilities 2025-01-28 22:09:06 +02:00
2cd03eceaa Add more helper methods for managing Git repos 2025-01-28 22:09:06 +02:00
d8feec325a Fix centered window location on X11 2025-01-28 22:09:05 +02:00
71b7f110e6 Fix initial position of Tooltips 2025-01-28 22:09:05 +02:00
Wojtek Figat
1b04c9a7b1 Another attempt to fix CD builds stability 2025-01-28 14:30:57 +01:00
Wojtek Figat
6a27e5338a Fix float precision issue when drawing curve or timeline time axes
#2455
2025-01-28 12:48:19 +01:00
Wojtek Figat
5ad323c7cb Fix showing whole curve if its empty 2025-01-28 12:44:52 +01:00
Chandler Cox
9c065d55e0 Change to use view CM and set inital ui mode to use if the prefab has ui. 2025-01-27 18:02:54 -06:00
10a906d51b Apply patches to rapidjson 2025-01-15 00:23:30 +02:00
f61779119b Update rapidjson to latest version
Commit d621dc9e9c77f81e5c8a35b8dcc16dcd63351321 in Tencent/rapidjson
2025-01-15 00:23:30 +02:00
Chandler Cox
0991628a78 Add UImode switch to prefab window. 2024-11-29 16:47:07 -06:00
xxSeys1
703e83cd48 improve ray direction not normalized assertion message 2024-10-15 21:25:30 +02:00
xxSeys1
a50c21cf36 add audio volume and muted in game panel tab rmb menu 2024-10-09 17:19:00 +02:00
Chandler Cox
ecb80e0f34 Add context to drag drop for object ref editor. 2024-09-27 18:26:37 -05:00
Chandler Cox
aded4bfdeb Add context to object referece control to narrow finding actors and scripts 2024-09-27 17:49:44 -05:00
davevanegdom
22764f5362 Improved SceneNodeDoubleClick names 2023-09-23 23:28:59 +02:00
davevanegdom
1b84f57a5b Small optimization 2023-09-23 03:24:19 +02:00
davevanegdom
23f4a82bbc Double click actions + open prefab ctxmenu 2023-09-22 18:31:54 +02:00
davevanegdom
9fbfc83535 Editor order cleanup 2023-09-19 14:19:38 +02:00
davevanegdom
ad8d84bfd7 Revert "Surface node body responds to mouse events"
This reverts commit d9b3443818.
2023-09-19 14:16:40 +02:00
davevanegdom
4257f1e2ac Color settings for Debug and Output log 2023-09-19 14:10:25 +02:00
davevanegdom
8166970038 Merge remote-tracking branch 'upstream/master' into DebugOutputImprovements 2023-09-19 14:09:51 +02:00
davevanegdom
88530606df Merge remote-tracking branch 'upstream/master' into ContentContextCondition 2023-09-19 01:10:51 +02:00
davevanegdom
d9b3443818 Surface node body responds to mouse events 2023-09-19 01:09:05 +02:00
285 changed files with 3974 additions and 1747 deletions

View File

@@ -1,13 +1,13 @@
name: Continuous Deployment name: Continuous Deployment
on: on:
schedule: schedule:
- cron: '15 4 * * *' - cron: '15 6 * * *'
workflow_dispatch: workflow_dispatch:
env: env:
DOTNET_NOLOGO: true DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: false DOTNET_CLI_TELEMETRY_OPTOUT: false
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=10 -c lfs.transfer.maxretries=2' GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
jobs: jobs:
@@ -84,7 +84,7 @@ jobs:
- name: Checkout LFS - name: Checkout LFS
run: | run: |
git lfs version git lfs version
GIT_TRACE=1 GIT_TRANSFER_TRACE=1 git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev

View File

@@ -1,4 +1,4 @@
# Redirect to our own Git LFS server # Redirect to our own Git LFS server
[lfs] [lfs]
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs" #url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
locksverify = false locksverify = false

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.

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/Editor/Grid.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -15,7 +15,7 @@ if errorlevel 1 goto BuildToolFailed
:: Build bindings for all editor configurations :: Build bindings for all editor configurations
echo Building C# bindings... echo Building C# bindings...
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
popd popd
echo Done! echo Done!

View File

@@ -14,4 +14,4 @@ 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,FlaxGame

View File

@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/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=x64 -platform=Linux --buildTargets=FlaxEditor Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame

View File

@@ -1,9 +1,11 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System; using System;
using System.Linq;
using FlaxEditor.Content.Create; using FlaxEditor.Content.Create;
using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors; using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Scripting;
using FlaxEditor.Windows; using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
@@ -84,18 +86,67 @@ namespace FlaxEditor.Content
if (_element != null) if (_element != null)
{ {
// Define the rule for the types that can be used to create a json data asset _element.CustomControl.CheckValid += OnCheckValidJsonAssetType;
_element.CustomControl.CheckValid += type =>
type.Type != null &&
type.IsClass &&
type.Type.IsVisible &&
!type.IsAbstract &&
!type.IsGenericType &&
type.Type.GetConstructor(Type.EmptyTypes) != null &&
!typeof(FlaxEngine.GUI.Control).IsAssignableFrom(type.Type) &&
!typeof(FlaxEngine.Object).IsAssignableFrom(type.Type);
} }
} }
private static Type[] BlacklistedClasses =
[
typeof(System.Attribute),
typeof(FlaxEngine.Object),
typeof(FlaxEngine.GUI.Control),
];
private static Type[] BlacklistedStructs =
[
typeof(Float2),
typeof(Float3),
typeof(Float4),
typeof(Double2),
typeof(Double3),
typeof(Double4),
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Half2),
typeof(Half3),
typeof(Half4),
typeof(Int2),
typeof(Int3),
typeof(Int4),
typeof(Transform),
typeof(Quaternion),
typeof(BoundingBox),
typeof(BoundingSphere),
typeof(BoundingFrustum),
typeof(Ray),
typeof(Plane),
typeof(Matrix),
typeof(Color),
typeof(Color32),
typeof(FloatR11G11B10),
typeof(FloatR10G10B10A2),
typeof(FlaxEngine.Half),
];
private static bool OnCheckValidJsonAssetType(ScriptType type)
{
// Define the rule for the types that can be used to create a json data asset
var mType = type.Type;
if (mType == null ||
type.IsAbstract ||
type.IsStatic ||
type.IsGenericType ||
!mType.IsVisible)
return false;
if (type.IsClass)
return mType.GetConstructor(Type.EmptyTypes) != null && BlacklistedClasses.FirstOrDefault(x => x.IsAssignableFrom(mType)) == null;
if (type.IsStructure)
return !type.IsPrimitive &&
!type.IsVoid &&
!BlacklistedStructs.Contains(mType);
return false;
}
} }
} }
@@ -175,7 +226,7 @@ namespace FlaxEditor.Content
{ {
_thumbnail = SpriteHandle.Invalid; _thumbnail = SpriteHandle.Invalid;
} }
/// <summary> /// <summary>
/// Constructor with overriden thumbnail. /// Constructor with overriden thumbnail.
/// </summary> /// </summary>
@@ -196,7 +247,7 @@ namespace FlaxEditor.Content
{ {
Editor.SaveJsonAsset(outputPath, new T()); Editor.SaveJsonAsset(outputPath, new T());
} }
/// <inheritdoc /> /// <inheritdoc />
public override AssetItem ConstructItem(string path, string typeName, ref Guid id) public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{ {

View File

@@ -496,7 +496,7 @@ namespace FlaxEditor.Content.Thumbnails
// Prepare requests // Prepare requests
bool isAnyReady = false; bool isAnyReady = false;
int checks = Mathf.Min(10, _requests.Count); int checks = Mathf.Min(10, _requests.Count);
for (int i = 0; i < checks; i++) for (int i = 0; i < checks && i < _requests.Count; i++)
{ {
var request = _requests[i]; var request = _requests[i];
try try

View File

@@ -1277,6 +1277,8 @@ bool CookAssetsStep::Perform(CookingData& data)
assetStats.Count++; assetStats.Count++;
assetStats.ContentSize += FileSystem::GetFileSize(cookedFilePath); assetStats.ContentSize += FileSystem::GetFileSize(cookedFilePath);
LOG(Info, "Cooked size of {0}: {1}KB", assetId, (FileSystem::GetFileSize(cookedFilePath) / (1024)));
if (packageBuilder.Add(data, i->Value, cookedFilePath)) if (packageBuilder.Add(data, i->Value, cookedFilePath))
return true; return true;
} }

View File

@@ -415,9 +415,9 @@ bool DeployDataStep::Perform(CookingData& data)
data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture")); data.AddRootEngineAsset(TEXT("Engine/Textures/NormalTexture"));
data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture")); data.AddRootEngineAsset(TEXT("Engine/Textures/BlackTexture"));
data.AddRootEngineAsset(TEXT("Engine/Textures/WhiteTexture")); data.AddRootEngineAsset(TEXT("Engine/Textures/WhiteTexture"));
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensStarburst")); //data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensStarburst"));
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensColor")); //data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensColor"));
data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensDirt")); //data.AddRootEngineAsset(TEXT("Engine/Textures/DefaultLensDirt"));
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Circle")); data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Circle"));
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Hexagon")); data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Hexagon"));
data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Octagon")); data.AddRootEngineAsset(TEXT("Engine/Textures/Bokeh/Octagon"));

View File

@@ -195,6 +195,15 @@ namespace FlaxEditor.CustomEditors
Presenter.AfterLayout?.Invoke(layout); Presenter.AfterLayout?.Invoke(layout);
} }
/// <inheritdoc />
protected override void Deinitialize()
{
Editor = null;
_overrideEditor = null;
base.Deinitialize();
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnModified() protected override void OnModified()
{ {

View File

@@ -68,12 +68,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Use default prefab instance as a reference for the editor // Use default prefab instance as a reference for the editor
Values.SetReferenceValue(prefabInstance); Values.SetReferenceValue(prefabInstance);
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter) // Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
var prefabId = prefab.ID;
Editor.GetPrefabNestedObject(ref prefabId, ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
var panel = layout.CustomContainer<UniformGridPanel>();
panel.CustomControl.Height = 20.0f;
panel.CustomControl.SlotsVertically = 1;
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
{ {
// Add some UI var targetPrefab = nestedPrefab ?? prefab;
var panel = layout.CustomContainer<UniformGridPanel>();
panel.CustomControl.Height = 20.0f;
panel.CustomControl.SlotsVertically = 1;
panel.CustomControl.SlotsHorizontally = 3; panel.CustomControl.SlotsHorizontally = 3;
// Selecting actor prefab asset // Selecting actor prefab asset
@@ -81,17 +85,21 @@ namespace FlaxEditor.CustomEditors.Dedicated
selectPrefab.Button.Clicked += () => selectPrefab.Button.Clicked += () =>
{ {
Editor.Instance.Windows.ContentWin.ClearItemsSearch(); Editor.Instance.Windows.ContentWin.ClearItemsSearch();
Editor.Instance.Windows.ContentWin.Select(prefab); Editor.Instance.Windows.ContentWin.Select(targetPrefab);
}; };
// Edit selected prefab asset // Edit selected prefab asset
var editPrefab = panel.Button("Edit Prefab"); var editPrefab = panel.Button("Edit Prefab");
editPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(prefab.ID)); editPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(targetPrefab.ID));
// Viewing changes applied to this actor
var viewChanges = panel.Button("View Changes");
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
} }
else
{
panel.CustomControl.SlotsHorizontally = 1;
}
// Viewing changes applied to this actor
var viewChanges = panel.Button("View Changes");
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
// Link event to update editor on prefab apply // Link event to update editor on prefab apply
_linkedPrefabId = prefab.ID; _linkedPrefabId = prefab.ID;
@@ -198,7 +206,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
if (_linkedPrefabId != Guid.Empty) if (_linkedPrefabId != Guid.Empty)
{ {
_linkedPrefabId = Guid.Empty; _linkedPrefabId = Guid.Empty;
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplying; Editor.Instance.Prefabs.PrefabApplying -= OnPrefabApplying;
Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied; Editor.Instance.Prefabs.PrefabApplied -= OnPrefabApplied;
} }
} }

View File

@@ -15,13 +15,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
private int _firstTimeShow; private int _firstTimeShow;
private BezierCurveEditor<T> _curve; private BezierCurveEditor<T> _curve;
private Splitter _splitter; private Splitter _splitter;
private string _heightCachedPath;
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var item = layout.CustomContainer<BezierCurveEditor<T>>(); var item = layout.CustomContainer<BezierCurveEditor<T>>();
_curve = item.CustomControl; _curve = item.CustomControl;
_curve.Height = 120.0f; var height = 120.0f;
var presenter = Presenter;
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
{
// Try to restore curve height
_heightCachedPath = layout.GetLayoutCachePath("Height");
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
height = cachedHeight;
}
_curve.Height = height;
_curve.Edited += OnCurveEdited; _curve.Edited += OnCurveEdited;
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing) _firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
_splitter = new Splitter _splitter = new Splitter
@@ -45,7 +55,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
private void OnSplitterMoved(Float2 location) private void OnSplitterMoved(Float2 location)
{ {
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f); _curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
// Cache curve height
if (_heightCachedPath != null)
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -133,13 +147,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
private int _firstTimeShow; private int _firstTimeShow;
private LinearCurveEditor<T> _curve; private LinearCurveEditor<T> _curve;
private Splitter _splitter; private Splitter _splitter;
private string _heightCachedPath;
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
var item = layout.CustomContainer<LinearCurveEditor<T>>(); var item = layout.CustomContainer<LinearCurveEditor<T>>();
_curve = item.CustomControl; _curve = item.CustomControl;
_curve.Height = 120.0f; var height = 120.0f;
var presenter = Presenter;
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
{
// Try to restore curve height
_heightCachedPath = layout.GetLayoutCachePath("Height");
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
height = cachedHeight;
}
_curve.Height = height;
_curve.Edited += OnCurveEdited; _curve.Edited += OnCurveEdited;
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing) _firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
_splitter = new Splitter _splitter = new Splitter
@@ -164,6 +188,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
private void OnSplitterMoved(Float2 location) private void OnSplitterMoved(Float2 location)
{ {
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f); _curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
// Cache curve height
if (_heightCachedPath != null)
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -1057,6 +1057,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
protected override void Deinitialize() protected override void Deinitialize()
{ {
_scriptToggles = null; _scriptToggles = null;
_scripts.Clear();
base.Deinitialize(); base.Deinitialize();
} }

View File

@@ -123,7 +123,9 @@ namespace FlaxEditor.CustomEditors.Editors
{ {
base.Refresh(); base.Refresh();
if (!HasDifferentValues) var differentValues = HasDifferentValues;
Picker.DifferentValues = differentValues;
if (!differentValues)
{ {
_isRefreshing = true; _isRefreshing = true;
var value = Values[0]; var value = Values[0];
@@ -375,12 +377,9 @@ namespace FlaxEditor.CustomEditors.Editors
{ {
base.Refresh(); base.Refresh();
if (!HasDifferentValues) _isRefreshing = true;
{ _textBox.Text = HasDifferentValues ? "Multiple Values" : GetPath();
_isRefreshing = true; _isRefreshing = false;
_textBox.Text = GetPath();
_isRefreshing = false;
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -26,6 +26,8 @@ namespace FlaxEditor.CustomEditors.Editors
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
_label = layout.ClickableLabel(Path).CustomControl; _label = layout.ClickableLabel(Path).CustomControl;
_label.Margin = new Margin(0, 20.0f, 0, 0);
_label.ClipText = true;
_label.RightClick += ShowPicker; _label.RightClick += ShowPicker;
var button = new Button var button = new Button
{ {

View File

@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Drag;
using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph;
using FlaxEditor.SceneGraph.GUI; using FlaxEditor.SceneGraph.GUI;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
@@ -40,6 +42,11 @@ namespace FlaxEditor.CustomEditors.Editors
private DragScripts _dragScripts; private DragScripts _dragScripts;
private DragHandlers _dragHandlers; private DragHandlers _dragHandlers;
/// <summary>
/// The presenter using this control.
/// </summary>
public IPresenterOwner PresenterContext;
/// <summary> /// <summary>
/// Gets or sets the allowed objects type (given type and all sub classes). Must be <see cref="Object"/> type of any subclass. /// Gets or sets the allowed objects type (given type and all sub classes). Must be <see cref="Object"/> type of any subclass.
/// </summary> /// </summary>
@@ -129,6 +136,11 @@ namespace FlaxEditor.CustomEditors.Editors
/// </summary> /// </summary>
public Func<Object, ScriptType, bool> CheckValid; public Func<Object, ScriptType, bool> CheckValid;
/// <summary>
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
/// </summary>
public bool DifferentValues;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FlaxObjectRefPickerControl"/> class. /// Initializes a new instance of the <see cref="FlaxObjectRefPickerControl"/> class.
/// </summary> /// </summary>
@@ -154,7 +166,7 @@ namespace FlaxEditor.CustomEditors.Editors
Value = actor; Value = actor;
RootWindow.Focus(); RootWindow.Focus();
Focus(); Focus();
}); }, PresenterContext);
} }
else else
{ {
@@ -163,7 +175,7 @@ namespace FlaxEditor.CustomEditors.Editors
Value = script; Value = script;
RootWindow.Focus(); RootWindow.Focus();
Focus(); Focus();
}); }, PresenterContext);
} }
} }
@@ -197,7 +209,14 @@ namespace FlaxEditor.CustomEditors.Editors
Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal); Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal);
// Check if has item selected // Check if has item selected
if (isSelected) if (DifferentValues)
{
// Draw info
Render2D.PushClip(nameRect);
Render2D.DrawText(style.FontMedium, Type != null ? $"Multiple Values ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? style.ForegroundGrey : style.ForegroundGrey.AlphaMultiplied(0.75f), TextAlignment.Near, TextAlignment.Center);
Render2D.PopClip();
}
else if (isSelected)
{ {
// Draw name // Draw name
Render2D.PushClip(nameRect); Render2D.PushClip(nameRect);
@@ -326,10 +345,19 @@ namespace FlaxEditor.CustomEditors.Editors
} }
else else
{ {
_linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode; if (PresenterContext is PropertiesWindow)
_linkedTreeNode.ExpandAllParents(); _linkedTreeNode = Editor.Instance.Scene.GetActorNode(actor).TreeNode;
Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true); else if (PresenterContext is PrefabWindow prefabWindow)
_linkedTreeNode.StartHighlight(); _linkedTreeNode = prefabWindow.Graph.Root.Find(actor).TreeNode;
if (_linkedTreeNode != null)
{
_linkedTreeNode.ExpandAllParents();
if (PresenterContext is PropertiesWindow)
Editor.Instance.Windows.SceneWin.SceneTreePanel.ScrollViewTo(_linkedTreeNode, true);
else if (PresenterContext is PrefabWindow prefabWindow)
(prefabWindow.Tree.Parent as Panel).ScrollViewTo(_linkedTreeNode, true);
_linkedTreeNode.StartHighlight();
}
} }
return true; return true;
} }
@@ -372,9 +400,20 @@ namespace FlaxEditor.CustomEditors.Editors
// Select object // Select object
if (_value is Actor actor) if (_value is Actor actor)
Editor.Instance.SceneEditing.Select(actor); {
if (PresenterContext is PropertiesWindow)
Editor.Instance.SceneEditing.Select(actor);
else if (PresenterContext is PrefabWindow prefabWindow)
prefabWindow.Select(prefabWindow.Graph.Root.Find(actor));
}
else if (_value is Script script && script.Actor) else if (_value is Script script && script.Actor)
Editor.Instance.SceneEditing.Select(script.Actor); {
var a = script.Actor;
if (PresenterContext is PropertiesWindow)
Editor.Instance.SceneEditing.Select(a);
else if (PresenterContext is PrefabWindow prefabWindow)
prefabWindow.Select(prefabWindow.Graph.Root.Find(a));
}
else if (_value is Asset asset) else if (_value is Asset asset)
Editor.Instance.Windows.ContentWin.Select(asset); Editor.Instance.Windows.ContentWin.Select(asset);
} }
@@ -415,13 +454,13 @@ namespace FlaxEditor.CustomEditors.Editors
// Ensure to have valid drag helpers (uses lazy init) // Ensure to have valid drag helpers (uses lazy init)
if (_dragActors == null) if (_dragActors == null)
_dragActors = new DragActors(x => IsValid(x.Actor)); _dragActors = new DragActors(ValidateDragActor);
if (_dragActorsWithScript == null) if (_dragActorsWithScript == null)
_dragActorsWithScript = new DragActors(ValidateDragActorWithScript); _dragActorsWithScript = new DragActors(ValidateDragActorWithScript);
if (_dragAssets == null) if (_dragAssets == null)
_dragAssets = new DragAssets(ValidateDragAsset); _dragAssets = new DragAssets(ValidateDragAsset);
if (_dragScripts == null) if (_dragScripts == null)
_dragScripts = new DragScripts(IsValid); _dragScripts = new DragScripts(ValidateDragScript);
if (_dragHandlers == null) if (_dragHandlers == null)
{ {
_dragHandlers = new DragHandlers _dragHandlers = new DragHandlers
@@ -446,6 +485,43 @@ namespace FlaxEditor.CustomEditors.Editors
return DragEffect; return DragEffect;
} }
private bool ValidateDragActor(ActorNode a)
{
if (!IsValid(a.Actor))
return false;
if (PresenterContext is PrefabWindow prefabWindow)
{
if (prefabWindow.Tree == a.TreeNode.ParentTree)
return true;
}
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
{
if (a.ParentScene != null)
return true;
}
return false;
}
private bool ValidateDragScript(Script script)
{
if (!IsValid(script))
return false;
if (PresenterContext is PrefabWindow prefabWindow)
{
var actorNode = prefabWindow.Graph.Root.Find(script.Actor);
if (actorNode != null)
return true;
}
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
{
if (script.Actor.HasScene)
return true;
}
return false;
}
private bool ValidateDragAsset(AssetItem assetItem) private bool ValidateDragAsset(AssetItem assetItem)
{ {
// Check if can accept assets // Check if can accept assets
@@ -464,7 +540,18 @@ namespace FlaxEditor.CustomEditors.Editors
private bool ValidateDragActorWithScript(ActorNode node) private bool ValidateDragActorWithScript(ActorNode node)
{ {
return node.Actor.Scripts.Any(IsValid); bool isCorrectContext = false;
if (PresenterContext is PrefabWindow prefabWindow)
{
if (prefabWindow.Tree == node.TreeNode.ParentTree)
isCorrectContext = true;
}
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
{
if (node.ParentScene != null)
isCorrectContext = true;
}
return node.Actor.Scripts.Any(IsValid) && isCorrectContext;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -536,6 +623,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (!HasDifferentTypes) if (!HasDifferentTypes)
{ {
_element = layout.Custom<FlaxObjectRefPickerControl>(); _element = layout.Custom<FlaxObjectRefPickerControl>();
_element.CustomControl.PresenterContext = Presenter.Owner;
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]); _element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value); _element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
} }
@@ -546,7 +634,9 @@ namespace FlaxEditor.CustomEditors.Editors
{ {
base.Refresh(); base.Refresh();
if (!HasDifferentValues) var differentValues = HasDifferentValues;
_element.CustomControl.DifferentValues = differentValues;
if (!differentValues)
{ {
_element.CustomControl.Value = Values[0] as Object; _element.CustomControl.Value = Values[0] as Object;
} }

View File

@@ -819,6 +819,15 @@ namespace FlaxEditor.CustomEditors.Editors
OnGroupsEnd(); OnGroupsEnd();
} }
/// <inheritdoc />
protected override void Deinitialize()
{
_visibleIfCaches = null;
_visibleIfPropertiesListsCache = null;
base.Deinitialize();
}
/// <inheritdoc /> /// <inheritdoc />
public override void Refresh() public override void Refresh()
{ {

View File

@@ -96,6 +96,20 @@ namespace FlaxEditor.CustomEditors
menu.Show(groupPanel, location); menu.Show(groupPanel, location);
} }
internal string GetLayoutCachePath(string name)
{
// Build group identifier (made of path from group titles)
var expandPath = name;
var container = this;
while (container != null && !(container is CustomEditorPresenter))
{
if (container.ContainerControl is DropPanel dropPanel)
expandPath = dropPanel.HeaderText + "/" + expandPath;
container = container._parent;
}
return expandPath;
}
/// <summary> /// <summary>
/// Adds new group element. /// Adds new group element.
/// </summary> /// </summary>
@@ -112,14 +126,7 @@ namespace FlaxEditor.CustomEditors
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0) if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
{ {
// Build group identifier (made of path from group titles) // Build group identifier (made of path from group titles)
var expandPath = title; var expandPath = GetLayoutCachePath(title);
var container = this;
while (container != null && !(container is CustomEditorPresenter))
{
if (container.ContainerControl is DropPanel dropPanel)
expandPath = dropPanel.HeaderText + "/" + expandPath;
container = container._parent;
}
// Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression) // Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression)
if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup) if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup)

View File

@@ -250,7 +250,7 @@ namespace FlaxEditor.CustomEditors
if (objA == null && objB is string objBStr && objBStr.Length == 0) if (objA == null && objB is string objBStr && objBStr.Length == 0)
return true; return true;
return Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals(objA, objB); return FlaxEngine.Json.JsonSerializer.ValueEquals(objA, objB);
} }
/// <summary> /// <summary>

View File

@@ -1686,9 +1686,6 @@ namespace FlaxEditor
[return: MarshalAs(UnmanagedType.U1)] [return: MarshalAs(UnmanagedType.U1)]
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot); internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetPrefabNestedObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static partial void Internal_GetPrefabNestedObject(IntPtr prefabId, IntPtr prefabObjectId, IntPtr outPrefabId, IntPtr outPrefabObjectId);
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))] [LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel); internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);

View File

@@ -48,6 +48,11 @@ namespace FlaxEditor.GUI
/// </summary> /// </summary>
public bool CanEdit = true; public bool CanEdit = true;
/// <summary>
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
/// </summary>
public bool DifferentValues;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AssetPicker"/> class. /// Initializes a new instance of the <see cref="AssetPicker"/> class.
/// </summary> /// </summary>
@@ -121,7 +126,13 @@ namespace FlaxEditor.GUI
if (CanEdit) if (CanEdit)
Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
if (Validator.SelectedItem != null) if (DifferentValues)
{
// No element selected
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
Render2D.DrawText(style.FontMedium, "Multiple\nValues", iconRect, style.Foreground, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
}
else if (Validator.SelectedItem != null)
{ {
// Draw item preview // Draw item preview
Validator.SelectedItem.DrawThumbnail(ref iconRect); Validator.SelectedItem.DrawThumbnail(ref iconRect);

View File

@@ -30,8 +30,10 @@ namespace FlaxEditor.GUI
internal bool _isMovingTangent; internal bool _isMovingTangent;
internal bool _movedView; internal bool _movedView;
internal bool _movedKeyframes; internal bool _movedKeyframes;
internal bool _toggledSelection;
private TangentPoint _movingTangent; private TangentPoint _movingTangent;
private Float2 _movingSelectionStart; private Float2 _movingSelectionStart;
private Float2 _movingSelectionStartPosLock;
private Float2[] _movingSelectionOffsets; private Float2[] _movingSelectionOffsets;
private Float2 _cmShowPos; private Float2 _cmShowPos;
@@ -56,12 +58,11 @@ namespace FlaxEditor.GUI
internal void UpdateSelection(ref Rectangle selectionRect) internal void UpdateSelection(ref Rectangle selectionRect)
{ {
// Find controls to select // Find controls to select
for (int i = 0; i < Children.Count; i++) var children = _children;
for (int i = 0; i < children.Count; i++)
{ {
if (Children[i] is KeyframePoint p) if (children[i] is KeyframePoint p)
{
p.IsSelected = p.Bounds.Intersects(ref selectionRect); p.IsSelected = p.Bounds.Intersects(ref selectionRect);
}
} }
_editor.UpdateTangents(); _editor.UpdateTangents();
} }
@@ -72,6 +73,7 @@ namespace FlaxEditor.GUI
_isMovingSelection = true; _isMovingSelection = true;
_movedKeyframes = false; _movedKeyframes = false;
var viewRect = _editor._mainPanel.GetClientArea(); var viewRect = _editor._mainPanel.GetClientArea();
_movingSelectionStartPosLock = location;
_movingSelectionStart = PointToKeyframes(location, ref viewRect); _movingSelectionStart = PointToKeyframes(location, ref viewRect);
if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count) if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count)
_movingSelectionOffsets = new Float2[_editor._points.Count]; _movingSelectionOffsets = new Float2[_editor._points.Count];
@@ -82,10 +84,17 @@ namespace FlaxEditor.GUI
internal void OnMove(Float2 location) internal void OnMove(Float2 location)
{ {
// Skip updating keyframes until move actual starts to be meaningful
if (Float2.Distance(ref _movingSelectionStartPosLock, ref location) < 1.5f)
return;
_movingSelectionStartPosLock = Float2.Minimum;
var viewRect = _editor._mainPanel.GetClientArea(); var viewRect = _editor._mainPanel.GetClientArea();
var locationKeyframes = PointToKeyframes(location, ref viewRect); var locationKeyframes = PointToKeyframes(location, ref viewRect);
var accessor = _editor.Accessor; var accessor = _editor.Accessor;
var components = accessor.GetCurveComponents(); var components = accessor.GetCurveComponents();
var snapEnabled = Root.GetKey(KeyboardKeys.Control);
var snapGrid = snapEnabled ? _editor.GetGridSnap() : Float2.One;
for (var i = 0; i < _editor._points.Count; i++) for (var i = 0; i < _editor._points.Count; i++)
{ {
var p = _editor._points[i]; var p = _editor._points[i];
@@ -122,7 +131,20 @@ namespace FlaxEditor.GUI
if (isFirstSelected) if (isFirstSelected)
{ {
time = locationKeyframes.X + offset.X; time = locationKeyframes.X + offset.X;
}
if (snapEnabled)
{
// Snap to the grid
var key = new Float2(time, value);
key = Float2.SnapToGrid(key, snapGrid);
time = key.X;
value = key.Y;
}
// Clamp and snap time to the valid range
if (isFirstSelected)
{
if (_editor.FPS.HasValue) if (_editor.FPS.HasValue)
{ {
float fps = _editor.FPS.Value; float fps = _editor.FPS.Value;
@@ -131,8 +153,6 @@ namespace FlaxEditor.GUI
time = Mathf.Clamp(time, minTime, maxTime); time = Mathf.Clamp(time, minTime, maxTime);
} }
// TODO: snapping keyframes to grid when moving
_editor.SetKeyframeInternal(p.Index, time, value, p.Component); _editor.SetKeyframeInternal(p.Index, time, value, p.Component);
} }
_editor.UpdateKeyframes(); _editor.UpdateKeyframes();
@@ -234,7 +254,11 @@ namespace FlaxEditor.GUI
var k = _editor.GetKeyframe(_movingTangent.Index); var k = _editor.GetKeyframe(_movingTangent.Index);
var kv = _editor.GetKeyframeValue(k); var kv = _editor.GetKeyframeValue(k);
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component); var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
_movingTangent.TangentValue = PointToKeyframes(location, ref viewRect).Y - value; var tangent = PointToKeyframes(location, ref viewRect).Y - value;
if (Root.GetKey(KeyboardKeys.Control))
tangent = Float2.SnapToGrid(new Float2(0, tangent), _editor.GetGridSnap()).Y; // Snap tangent over Y axis
tangent = tangent * _editor.ViewScale.X * 2;
_movingTangent.TangentValue = tangent;
_editor.UpdateTangents(); _editor.UpdateTangents();
Cursor = CursorType.SizeNS; Cursor = CursorType.SizeNS;
_movedKeyframes = true; _movedKeyframes = true;
@@ -283,6 +307,7 @@ namespace FlaxEditor.GUI
} }
// Cache data // Cache data
_toggledSelection = false;
_isMovingSelection = false; _isMovingSelection = false;
_isMovingTangent = false; _isMovingTangent = false;
_mousePos = location; _mousePos = location;
@@ -305,13 +330,7 @@ namespace FlaxEditor.GUI
{ {
if (_leftMouseDown) if (_leftMouseDown)
{ {
if (Root.GetKey(KeyboardKeys.Control)) if (Root.GetKey(KeyboardKeys.Shift))
{
// Toggle selection
keyframe.IsSelected = !keyframe.IsSelected;
_editor.UpdateTangents();
}
else if (Root.GetKey(KeyboardKeys.Shift))
{ {
// Select range // Select range
keyframe.IsSelected = true; keyframe.IsSelected = true;
@@ -335,10 +354,14 @@ namespace FlaxEditor.GUI
else if (!keyframe.IsSelected) else if (!keyframe.IsSelected)
{ {
// Select node // Select node
if (_editor.KeyframesEditorContext != null) if (!Root.GetKey(KeyboardKeys.Control))
_editor.KeyframesEditorContext.OnKeyframesDeselect(_editor); {
else if (_editor.KeyframesEditorContext != null)
_editor.ClearSelection(); _editor.KeyframesEditorContext.OnKeyframesDeselect(_editor);
else
_editor.ClearSelection();
}
_toggledSelection = true;
keyframe.IsSelected = true; keyframe.IsSelected = true;
_editor.UpdateTangents(); _editor.UpdateTangents();
} }
@@ -429,6 +452,12 @@ namespace FlaxEditor.GUI
else else
OnMoveEnd(location); OnMoveEnd(location);
} }
// Toggle selection
else if (!_toggledSelection && Root.GetKey(KeyboardKeys.Control) && GetChildAt(location) is KeyframePoint keyframe)
{
keyframe.IsSelected = !keyframe.IsSelected;
_editor.UpdateTangents();
}
_isMovingSelection = false; _isMovingSelection = false;
_isMovingTangent = false; _isMovingTangent = false;
@@ -514,11 +543,11 @@ namespace FlaxEditor.GUI
{ {
if (base.OnMouseDoubleClick(location, button)) if (base.OnMouseDoubleClick(location, button))
return true; return true;
// Add keyframe on double click // Add keyframe on double click
var child = GetChildAt(location); var child = GetChildAt(location);
if (child is not KeyframePoint && if (child is not KeyframePoint &&
child is not TangentPoint && child is not TangentPoint &&
_editor.KeyframesCount < _editor.MaxKeyframes) _editor.KeyframesCount < _editor.MaxKeyframes)
{ {
var viewRect = _editor._mainPanel.GetClientArea(); var viewRect = _editor._mainPanel.GetClientArea();
@@ -545,7 +574,7 @@ namespace FlaxEditor.GUI
var viewRect = _editor._mainPanel.GetClientArea(); var viewRect = _editor._mainPanel.GetClientArea();
var locationInKeyframes = PointToKeyframes(location, ref viewRect); var locationInKeyframes = PointToKeyframes(location, ref viewRect);
var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect); var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
// Scale relative to the curve size // Scale relative to the curve size
var scale = new Float2(delta * 0.1f); var scale = new Float2(delta * 0.1f);
_editor._mainPanel.GetDesireClientArea(out var mainPanelArea); _editor._mainPanel.GetDesireClientArea(out var mainPanelArea);

View File

@@ -163,10 +163,11 @@ namespace FlaxEditor.GUI
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {
var style = Style.Current;
var rect = new Rectangle(Float2.Zero, Size); var rect = new Rectangle(Float2.Zero, Size);
var color = Editor.ShowCollapsed ? Color.Gray : Editor.Colors[Component]; var color = Editor.ShowCollapsed ? style.ForegroundDisabled : Editor.Colors[Component];
if (IsSelected) if (IsSelected)
color = Editor.ContainsFocus ? Color.YellowGreen : Color.Lerp(Color.Gray, Color.YellowGreen, 0.4f); color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
if (IsMouseOver) if (IsMouseOver)
color *= 1.1f; color *= 1.1f;
Render2D.FillRectangle(rect, color); Render2D.FillRectangle(rect, color);
@@ -244,14 +245,19 @@ namespace FlaxEditor.GUI
set => Editor.SetKeyframeTangentInternal(Index, IsIn, Component, value); set => Editor.SetKeyframeTangentInternal(Index, IsIn, Component, value);
} }
internal float TangentOffset => 50.0f / Editor.ViewScale.X;
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {
var style = Style.Current;
var thickness = 6.0f / Mathf.Max(Editor.ViewScale.X, 1.0f);
var size = Size;
var pointPos = PointFromParent(Point.Center); var pointPos = PointFromParent(Point.Center);
Render2D.DrawLine(Size * 0.5f, pointPos, Color.Gray); Render2D.DrawLine(size * 0.5f, pointPos, style.ForegroundDisabled, thickness);
var rect = new Rectangle(Float2.Zero, Size); var rect = new Rectangle(Float2.Zero, size);
var color = Color.MediumVioletRed; var color = style.BorderSelected;
if (IsMouseOver) if (IsMouseOver)
color *= 1.1f; color *= 1.1f;
Render2D.FillRectangle(rect, color); Render2D.FillRectangle(rect, color);
@@ -289,7 +295,7 @@ namespace FlaxEditor.GUI
/// <summary> /// <summary>
/// The curve time/value axes tick steps. /// The curve time/value axes tick steps.
/// </summary> /// </summary>
protected float[] TickSteps = Utilities.Utils.CurveTickSteps; protected double[] TickSteps = Utilities.Utils.CurveTickSteps;
/// <summary> /// <summary>
/// The curve contents area. /// The curve contents area.
@@ -442,7 +448,7 @@ namespace FlaxEditor.GUI
_mainPanel = new Panel(ScrollBars.Both) _mainPanel = new Panel(ScrollBars.Both)
{ {
ScrollMargin = new Margin(150.0f), ScrollMargin = new Margin(150.0f),
AlwaysShowScrollbars = true, AlwaysShowScrollbars = false,
AnchorPreset = AnchorPresets.StretchAll, AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero, Offsets = Margin.Zero,
Parent = this Parent = this
@@ -668,26 +674,82 @@ namespace FlaxEditor.GUI
OnEditingEnd(); OnEditingEnd();
} }
private void ShowCurve(bool selectedOnly)
{
if (_points.Count == 0)
return;
int pass = 1;
REDO:
// Get curve bounds in Keyframes (time and value)
Float2 posMin = Float2.Maximum, posMax = Float2.Minimum;
// TODO: include bezier curve bounds calculation to handle curve outside the bounds made out of points
foreach (var point in _points)
{
if (selectedOnly && !point.IsSelected)
continue;
var pos = point.Point;
Float2.Min(ref posMin, ref pos, out posMin);
Float2.Max(ref posMax, ref pos, out posMax);
}
// Apply margin around the area
var posMargin = (posMax - posMin) * 0.05f;
posMin -= posMargin;
posMax += posMargin;
// Convert from Keyframes to Contents
_mainPanel.GetDesireClientArea(out var viewRect);
PointFromKeyframesToContents(ref posMin, ref viewRect);
PointFromKeyframesToContents(ref posMax, ref viewRect);
var tmp = posMin;
Float2.Min(ref posMin, ref posMax, out posMin);
Float2.Max(ref posMax, ref tmp, out posMax);
var contentsSize = posMax - posMin;
// Convert from Contents to Main Panel
posMin = _contents.PointToParent(posMin);
posMax = _contents.PointToParent(posMax);
tmp = posMin;
Float2.Min(ref posMin, ref posMax, out posMin);
Float2.Max(ref posMax, ref tmp, out posMax);
// Update zoom (leave unchanged when focusing a single point)
var zoomMask = EnableZoom;
if (Mathf.IsZero(posMargin.X))
zoomMask &= ~UseMode.Horizontal;
if (Mathf.IsZero(posMargin.Y))
zoomMask &= ~UseMode.Vertical;
ViewScale = ApplyUseModeMask(zoomMask, viewRect.Size / contentsSize, ViewScale);
// Update scroll (attempt to center the area when it's smaller than the view)
Float2 viewOffset = -posMin;
Float2 viewSize = _mainPanel.Size;
Float2 viewSizeLeft = viewSize - Float2.Clamp(posMax - posMin, Float2.Zero, viewSize);
viewOffset += viewSizeLeft * 0.5f;
viewOffset = ApplyUseModeMask(EnablePanning, viewOffset, _mainPanel.ViewOffset);
_mainPanel.ViewOffset = viewOffset;
// Do it multiple times so the view offset can be properly calculate once the view scale gets changes
if (pass++ <= 2)
goto REDO;
UpdateKeyframes();
}
/// <summary>
/// Focuses the view on the selected keyframes.
/// </summary>
public void FocusSelection()
{
// Fallback to showing whole curve if nothing is selected
ShowCurve(SelectionCount != 0);
}
/// <inheritdoc /> /// <inheritdoc />
public override void ShowWholeCurve() public override void ShowWholeCurve()
{ {
_mainPanel.GetDesireClientArea(out var mainPanelArea); ShowCurve(false);
ViewScale = ApplyUseModeMask(EnableZoom, mainPanelArea.Size / _contents.Size, ViewScale);
Float2 minPos = Float2.Maximum;
foreach (var point in _points)
{
var pos = point.PointToParent(point.Location);
Float2.Min(ref minPos, ref pos, out minPos);
}
var minPosPoint = _contents.PointToParent(ref minPos);
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
if (_mainPanel.HScrollBar != null)
_mainPanel.HScrollBar.TargetValue = scroll.X;
if (_mainPanel.VScrollBar != null)
_mainPanel.VScrollBar.TargetValue = scroll.Y;
UpdateKeyframes();
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -766,10 +828,7 @@ namespace FlaxEditor.GUI
point = _contents.PointFromParent(point); point = _contents.PointFromParent(point);
// Contents -> Keyframes // Contents -> Keyframes
return new Float2( return PointFromContentsToKeyframes(ref point, ref curveContentAreaBounds);
(point.X + _contents.Location.X) / UnitsPerSecond,
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
);
} }
/// <summary> /// <summary>
@@ -781,10 +840,7 @@ namespace FlaxEditor.GUI
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds) protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
{ {
// Keyframes -> Contents // Keyframes -> Contents
point = new Float2( PointFromKeyframesToContents(ref point, ref curveContentAreaBounds);
point.X * UnitsPerSecond - _contents.Location.X,
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
);
// Contents -> Main Panel // Contents -> Main Panel
point = _contents.PointToParent(point); point = _contents.PointToParent(point);
@@ -793,11 +849,27 @@ namespace FlaxEditor.GUI
return _mainPanel.PointToParent(point); return _mainPanel.PointToParent(point);
} }
internal Float2 PointFromContentsToKeyframes(ref Float2 point, ref Rectangle curveContentAreaBounds)
{
return new Float2(
(point.X + _contents.Location.X) / UnitsPerSecond,
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
);
}
internal void PointFromKeyframesToContents(ref Float2 point, ref Rectangle curveContentAreaBounds)
{
point = new Float2(
point.X * UnitsPerSecond - _contents.Location.X,
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
);
}
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange) private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
{ {
Utilities.Utils.DrawCurveTicks((float tick, float strength) => Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
{ {
var p = PointFromKeyframes(axis * tick, ref viewRect); var p = PointFromKeyframes(axis * (float)tick, ref viewRect);
// Draw line // Draw line
var lineRect = new Rectangle var lineRect = new Rectangle
@@ -820,6 +892,24 @@ namespace FlaxEditor.GUI
}, TickSteps, ref _tickStrengths, min, max, pixelRange); }, TickSteps, ref _tickStrengths, min, max, pixelRange);
} }
private void SetupGrid(out Float2 min, out Float2 max, out Float2 pixelRange)
{
var viewRect = _mainPanel.GetClientArea();
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect);
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
min = Float2.Min(upperLeft, bottomRight);
max = Float2.Max(upperLeft, bottomRight);
pixelRange = (max - min) * ViewScale * UnitsPerSecond;
}
private Float2 GetGridSnap()
{
SetupGrid(out var min, out var max, out var pixelRange);
return new Float2(Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.X, max.X, pixelRange.X),
Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.Y, max.Y, pixelRange.Y));
}
/// <summary> /// <summary>
/// Draws the curve. /// Draws the curve.
/// </summary> /// </summary>
@@ -849,12 +939,7 @@ namespace FlaxEditor.GUI
// Draw time and values axes // Draw time and values axes
if (ShowAxes != UseMode.Off) if (ShowAxes != UseMode.Off)
{ {
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect); SetupGrid(out var min, out var max, out var pixelRange);
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
var min = Float2.Min(upperLeft, bottomRight);
var max = Float2.Max(upperLeft, bottomRight);
var pixelRange = (max - min) * ViewScale * UnitsPerSecond;
Render2D.PushClip(ref viewRect); Render2D.PushClip(ref viewRect);
@@ -939,7 +1024,7 @@ namespace FlaxEditor.GUI
} }
else if (options.FocusSelection.Process(this)) else if (options.FocusSelection.Process(this))
{ {
ShowWholeCurve(); FocusSelection();
return true; return true;
} }
@@ -2200,7 +2285,7 @@ namespace FlaxEditor.GUI
var tangent = t.TangentValue; var tangent = t.TangentValue;
var direction = t.IsIn ? -1.0f : 1.0f; var direction = t.IsIn ? -1.0f : 1.0f;
var offset = 30.0f; var offset = t.TangentOffset;
var location = GetKeyframePoint(ref k, selectedComponent); var location = GetKeyframePoint(ref k, selectedComponent);
t.Size = KeyframesSize / ViewScale; t.Size = KeyframesSize / ViewScale;
t.Location = new Float2 t.Location = new Float2
@@ -2227,6 +2312,18 @@ namespace FlaxEditor.GUI
} }
} }
/// <inheritdoc />
protected override void SetScaleInternal(ref Float2 scale)
{
base.SetScaleInternal(ref scale);
if (!_showCollapsed)
{
// Refresh keyframes when zooming (their size depends on the scale)
UpdateKeyframes();
}
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnShowContextMenu(ContextMenu.ContextMenu cm, int selectionCount) protected override void OnShowContextMenu(ContextMenu.ContextMenu cm, int selectionCount)
{ {

View File

@@ -486,7 +486,7 @@ namespace FlaxEditor.GUI.Docking
{ {
base.Focus(); base.Focus();
SelectTab(); SelectTab(false);
BringToFront(); BringToFront();
} }

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System; using System;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -55,18 +57,26 @@ namespace FlaxEditor.GUI
private IsValidDelegate _isValid; private IsValidDelegate _isValid;
private Action<Actor> _selected; private Action<Actor> _selected;
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected) private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
{ {
_isValid = isValid; _isValid = isValid;
_selected = selected; _selected = selected;
ItemClicked += OnItemClicked; ItemClicked += OnItemClicked;
// TODO: use async thread to search scenes if (context is PropertiesWindow propertiesWindow || context == null)
for (int i = 0; i < Level.ScenesCount; i++)
{ {
Find(Level.GetScene(i)); // TODO: use async thread to search scenes
for (int i = 0; i < Level.ScenesCount; i++)
{
Find(Level.GetScene(i));
}
} }
else if (context is PrefabWindow prefabWindow)
{
Find(prefabWindow.Graph.MainActor);
}
SortItems(); SortItems();
} }
@@ -98,10 +108,11 @@ namespace FlaxEditor.GUI
/// <param name="showTargetLocation">The show target location.</param> /// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given actor item is valid to be used.</param> /// <param name="isValid">Event called to check if a given actor item is valid to be used.</param>
/// <param name="selected">Event called on actor item pick.</param> /// <param name="selected">Event called on actor item pick.</param>
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
/// <returns>The dialog.</returns> /// <returns>The dialog.</returns>
public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected) public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
{ {
var popup = new ActorSearchPopup(isValid, selected); var popup = new ActorSearchPopup(isValid, selected, context);
popup.Show(showTarget, showTargetLocation); popup.Show(showTarget, showTargetLocation);
return popup; return popup;
} }

View File

@@ -1,6 +1,8 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System; using System;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
@@ -66,18 +68,26 @@ namespace FlaxEditor.GUI
private IsValidDelegate _isValid; private IsValidDelegate _isValid;
private Action<Script> _selected; private Action<Script> _selected;
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected) private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
{ {
_isValid = isValid; _isValid = isValid;
_selected = selected; _selected = selected;
ItemClicked += OnItemClicked; ItemClicked += OnItemClicked;
// TODO: use async thread to search scenes if (context is PropertiesWindow propertiesWindow || context == null)
for (int i = 0; i < Level.ScenesCount; i++)
{ {
Find(Level.GetScene(i)); // TODO: use async thread to search scenes
for (int i = 0; i < Level.ScenesCount; i++)
{
Find(Level.GetScene(i));
}
} }
else if (context is PrefabWindow prefabWindow)
{
Find(prefabWindow.Graph.MainActor);
}
SortItems(); SortItems();
} }
@@ -113,10 +123,11 @@ namespace FlaxEditor.GUI
/// <param name="showTargetLocation">The show target location.</param> /// <param name="showTargetLocation">The show target location.</param>
/// <param name="isValid">Event called to check if a given script item is valid to be used.</param> /// <param name="isValid">Event called to check if a given script item is valid to be used.</param>
/// <param name="selected">Event called on script item pick.</param> /// <param name="selected">Event called on script item pick.</param>
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
/// <returns>The dialog.</returns> /// <returns>The dialog.</returns>
public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected) public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
{ {
var popup = new ScriptSearchPopup(isValid, selected); var popup = new ScriptSearchPopup(isValid, selected, context);
popup.Show(showTarget, showTargetLocation); popup.Show(showTarget, showTargetLocation);
return popup; return popup;
} }

View File

@@ -1,10 +1,13 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using FlaxEditor.History;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using CategoryAttribute = FlaxEngine.CategoryAttribute;
namespace FlaxEditor.GUI namespace FlaxEditor.GUI
{ {
@@ -101,11 +104,26 @@ namespace FlaxEditor.GUI
if (_isValid(type)) if (_isValid(type))
{ {
var attributes = type.GetAttributes(true); var attributes = type.GetAttributes(true);
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute || x is System.Runtime.CompilerServices.CompilerGeneratedAttribute) == null) if (IsHideAttributes(attributes))
{ {
var mType = type.Type; var mType = type.Type;
if (mType != null && mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal)) if (mType != null)
continue; {
// Skip if type is compiler-generated
if (mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal))
continue;
// Skip if outer type is hidden
if (mType.DeclaringType != null && IsHideAttributes(mType.DeclaringType.GetCustomAttributes(true)))
continue;
// Blacklist some types
if (typeof(TypeConverter).IsAssignableFrom(mType) ||
typeof(IHistoryAction).IsAssignableFrom(mType) ||
(mType.Namespace != null && mType.Namespace.StartsWith("Newtonsoft.Json")))
continue;
}
AddItem(new TypeItemView(type, attributes)); AddItem(new TypeItemView(type, attributes));
} }
} }
@@ -113,6 +131,17 @@ namespace FlaxEditor.GUI
SortItems(); SortItems();
} }
private bool IsHideAttributes(object[] attributes)
{
return attributes.FirstOrDefault(IsHideAttribute) == null;
}
private bool IsHideAttribute(object attr)
{
return attr is HideInEditorAttribute ||
attr is System.Runtime.CompilerServices.CompilerGeneratedAttribute;
}
private void OnItemClicked(Item item) private void OnItemClicked(Item item)
{ {
_selected(((TypeItemView)item).Type); _selected(((TypeItemView)item).Type);

View File

@@ -14,7 +14,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
class Background : ContainerControl class Background : ContainerControl
{ {
private readonly Timeline _timeline; private readonly Timeline _timeline;
private float[] _tickSteps; private double[] _tickSteps;
private float[] _tickStrengths; private float[] _tickStrengths;
private bool _isSelecting; private bool _isSelecting;
private Float2 _selectingStartPos = Float2.Minimum; private Float2 _selectingStartPos = Float2.Minimum;
@@ -176,9 +176,9 @@ namespace FlaxEditor.GUI.Timeline.GUI
// Draw vertical lines for time axis // Draw vertical lines for time axis
var pixelsInRange = _timeline.Zoom; var pixelsInRange = _timeline.Zoom;
var pixelRange = pixelsInRange * (max - min); var pixelRange = pixelsInRange * (max - min);
var tickRange = Utilities.Utils.DrawCurveTicks((float tick, float strength) => var tickRange = Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
{ {
var time = tick / _timeline.FramesPerSecond; var time = (float)tick / _timeline.FramesPerSecond;
var x = time * zoom + Timeline.StartOffset; var x = time * zoom + Timeline.StartOffset;
var lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength); var lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor); Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor);
@@ -233,20 +233,20 @@ namespace FlaxEditor.GUI.Timeline.GUI
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2); int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
var lStep = _tickSteps[l]; var lStep = _tickSteps[l];
var lNextStep = _tickSteps[l + 1]; var lNextStep = _tickSteps[l + 1];
int startTick = Mathf.FloorToInt(min / lStep); var startTick = Mathd.FloorToInt(min / lStep);
int endTick = Mathf.CeilToInt(max / lStep); var endTick = Mathd.CeilToInt(max / lStep);
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength); Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength); Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
for (int i = startTick; i <= endTick; i++) for (var i = startTick; i <= endTick; i++)
{ {
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0)) if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
continue; continue;
var tick = i * lStep; var tick = (decimal)lStep * i;
var time = tick / _timeline.FramesPerSecond; var time = (double)tick / _timeline.FramesPerSecond;
var x = time * zoom + Timeline.StartOffset; var x = (float)time * zoom + Timeline.StartOffset;
// Header line // Header line
var lineRect = new Rectangle(x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f); var lineRect = new Rectangle((float)x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f);
Render2D.FillRectangle(lineRect, lineColor); Render2D.FillRectangle(lineRect, lineColor);
// Time label // Time label

View File

@@ -8,7 +8,6 @@ using System.Text;
using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Options; using FlaxEditor.Options;
using FlaxEditor.Scripting;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json; using FlaxEngine.Json;

View File

@@ -264,7 +264,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
private void OnClickedSelect() private void OnClickedSelect()
{ {
ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor); ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor, null);
} }
private void OnClickedSelectActor(Image image, MouseButton button) private void OnClickedSelectActor(Image image, MouseButton button)

View File

@@ -19,12 +19,11 @@ namespace FlaxEditor.Gizmo
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
private struct Data private struct Data
{ {
public Matrix WorldMatrix;
public Matrix ViewProjectionMatrix; public Matrix ViewProjectionMatrix;
public Float4 GridColor; public Float4 GridColor;
public Float3 ViewPos; public Float3 ViewPos;
public float Far; public float Far;
public Float3 Padding; public Float3 ViewOrigin;
public float GridSize; public float GridSize;
} }
@@ -44,6 +43,7 @@ namespace FlaxEditor.Gizmo
{ {
UseSingleTarget = true; UseSingleTarget = true;
Location = PostProcessEffectLocation.Default; Location = PostProcessEffectLocation.Default;
Order = -100000; // Draw before any other editor shapes
_shader = FlaxEngine.Content.LoadAsyncInternal<Shader>("Shaders/Editor/Grid"); _shader = FlaxEngine.Content.LoadAsyncInternal<Shader>("Shaders/Editor/Grid");
} }
@@ -62,7 +62,6 @@ namespace FlaxEditor.Gizmo
Profiler.BeginEventGPU("Editor Grid"); Profiler.BeginEventGPU("Editor Grid");
var options = Editor.Instance.Options.Options; var options = Editor.Instance.Options.Options;
Float3 camPos = renderContext.View.WorldPosition;
float gridSize = renderContext.View.Far + 20000; float gridSize = renderContext.View.Far + 20000;
// Lazy-init resources // Lazy-init resources
@@ -97,10 +96,10 @@ namespace FlaxEditor.Gizmo
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
var vertices = new Float3[] var vertices = new Float3[]
{ {
new Float3(-gridSize + camPos.X, y, -gridSize + camPos.Z), new Float3(-gridSize, y, -gridSize),
new Float3(gridSize + camPos.X, y, gridSize + camPos.Z), new Float3(gridSize, y, gridSize),
new Float3(-gridSize + camPos.X, y, gridSize + camPos.Z), new Float3(-gridSize, y, gridSize),
new Float3(gridSize + camPos.X, y, -gridSize + camPos.Z), new Float3(gridSize, y, -gridSize),
}; };
fixed (Float3* ptr = vertices) fixed (Float3* ptr = vertices)
{ {
@@ -113,12 +112,12 @@ namespace FlaxEditor.Gizmo
{ {
var data = new Data(); var data = new Data();
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection); Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
data.WorldMatrix = Matrix.Identity;
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix); Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
data.ViewPos = renderContext.View.WorldPosition; data.ViewPos = renderContext.View.WorldPosition;
data.GridColor = options.Viewport.ViewportGridColor; data.GridColor = options.Viewport.ViewportGridColor;
data.Far = renderContext.View.Far; data.Far = renderContext.View.Far;
data.GridSize = options.Viewport.ViewportGridViewDistance; data.GridSize = options.Viewport.ViewportGridViewDistance;
data.ViewOrigin = renderContext.View.Origin;
context.UpdateCB(cb, new IntPtr(&data)); context.UpdateCB(cb, new IntPtr(&data));
} }

View File

@@ -85,6 +85,8 @@ namespace FlaxEditor.Gizmo
/// </summary> /// </summary>
public SelectionOutline() public SelectionOutline()
{ {
Order = -90000; // Draw before any other editor shapes (except grid gizmo)
_outlineMaterial = FlaxEngine.Content.LoadAsyncInternal<Material>("Editor/Gizmo/SelectionOutlineMaterial"); _outlineMaterial = FlaxEngine.Content.LoadAsyncInternal<Material>("Editor/Gizmo/SelectionOutlineMaterial");
if (_outlineMaterial) if (_outlineMaterial)
{ {

View File

@@ -115,6 +115,7 @@ namespace FlaxEditor.Gizmo
bool isCenter = _activeAxis == Axis.Center; bool isCenter = _activeAxis == Axis.Center;
renderContext.View.GetWorldMatrix(ref _gizmoWorld, out Matrix world); renderContext.View.GetWorldMatrix(ref _gizmoWorld, out Matrix world);
const sbyte sortOrder = 100; // Draw after any other editor shapes
const float gizmoModelsScale2RealGizmoSize = 0.075f; const float gizmoModelsScale2RealGizmoSize = 0.075f;
Mesh cubeMesh = _modelCube.LODs[0].Meshes[0]; Mesh cubeMesh = _modelCube.LODs[0].Meshes[0];
Mesh sphereMesh = _modelSphere.LODs[0].Meshes[0]; Mesh sphereMesh = _modelSphere.LODs[0].Meshes[0];
@@ -136,42 +137,42 @@ namespace FlaxEditor.Gizmo
Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3); transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3); transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(Mathf.Pi, out m2); Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3); transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane // XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX); MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3); cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane // ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY); MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY);
cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3); cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane // YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ); MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ);
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3); cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center sphere // Center sphere
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
break; break;
} }
@@ -186,22 +187,22 @@ namespace FlaxEditor.Gizmo
Matrix.RotationZ(Mathf.PiOverTwo, out m2); Matrix.RotationZ(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3); rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1); rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(-Mathf.PiOverTwo, out m2); Matrix.RotationX(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3); rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box // Center box
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
break; break;
} }
@@ -216,42 +217,42 @@ namespace FlaxEditor.Gizmo
Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref mx1, out m3); Matrix.Multiply(ref m2, ref mx1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX); MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3); scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY); MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3); scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(Mathf.Pi, out m2); Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ); MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3); scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane // XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX); MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3); cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane // ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ); MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ);
cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3); cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane // YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY); MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY);
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3); cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box // Center box
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2); Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3); sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
break; break;
} }
@@ -263,7 +264,7 @@ namespace FlaxEditor.Gizmo
Transform t = _vertexSnapObject?.Transform ?? _vertexSnapObjectTo.Transform; Transform t = _vertexSnapObject?.Transform ?? _vertexSnapObjectTo.Transform;
Vector3 p = t.LocalToWorld(_vertexSnapObject != null ? _vertexSnapPoint : _vertexSnapPointTo); Vector3 p = t.LocalToWorld(_vertexSnapObject != null ? _vertexSnapPoint : _vertexSnapPointTo);
Matrix matrix = new Transform(p, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld(); Matrix matrix = new Transform(p, t.Orientation, new Float3(gizmoModelsScale2RealGizmoSize)).GetWorld();
cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix); cubeMesh.Draw(ref renderContext, _materialSphere, ref matrix, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
} }
} }
} }

View File

@@ -150,7 +150,8 @@ namespace FlaxEditor
private float _mouseMoveSum; private float _mouseMoveSum;
private UndoMultiBlock _undoBlock; private UndoMultiBlock _undoBlock;
private View _view; private View _view;
private float[] _gridTickSteps = Utilities.Utils.CurveTickSteps, _gridTickStrengths; private double[] _gridTickSteps = Utilities.Utils.CurveTickSteps;
private float[] _gridTickStrengths;
private List<Widget> _widgets; private List<Widget> _widgets;
private Widget _activeWidget; private Widget _activeWidget;
@@ -564,9 +565,9 @@ namespace FlaxEditor
var linesColor = style.ForegroundDisabled.RGBMultiplied(0.5f); var linesColor = style.ForegroundDisabled.RGBMultiplied(0.5f);
var labelsColor = style.ForegroundDisabled; var labelsColor = style.ForegroundDisabled;
var labelsSize = 10.0f; var labelsSize = 10.0f;
Utilities.Utils.DrawCurveTicks((float tick, float strength) => Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
{ {
var p = _view.PointToParent(axis * tick); var p = _view.PointToParent(axis * (float)tick);
// Draw line // Draw line
var lineRect = new Rectangle var lineRect = new Rectangle

View File

@@ -504,7 +504,8 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
return false; return false;
const ISerializable::DeserializeStream& newRootData = **newRootDataPtr; const ISerializable::DeserializeStream& newRootData = **newRootDataPtr;
Guid prefabId, prefabObjectID; Guid prefabId, prefabObjectID;
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") && JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID")) if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") &&
JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
{ {
const auto nestedPrefab = Content::Load<Prefab>(prefabId); const auto nestedPrefab = Content::Load<Prefab>(prefabId);
if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID) if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID)
@@ -514,21 +515,6 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
return true; return true;
} }
DEFINE_INTERNAL_CALL(void) EditorInternal_GetPrefabNestedObject(Guid* prefabId, Guid* prefabObjectId, Guid* outPrefabId, Guid* outPrefabObjectId)
{
*outPrefabId = Guid::Empty;
*outPrefabObjectId = Guid::Empty;
const auto prefab = Content::Load<Prefab>(*prefabId);
if (!prefab)
return;
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(*prefabObjectId);
if (!prefabObjectDataPtr)
return;
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
JsonTools::GetGuidIfValid(*outPrefabId, prefabObjectData, "PrefabID");
JsonTools::GetGuidIfValid(*outPrefabObjectId, prefabObjectData, "PrefabObjectID");
}
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel) DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
{ {
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f; return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;

View File

@@ -12,11 +12,14 @@
#include "Engine/Scripting/ManagedCLR/MException.h" #include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h" #include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Content/Assets/VisualScript.h" #include "Engine/Content/Assets/VisualScript.h"
#include "Engine/Content/Content.h"
#include "Engine/CSG/CSGBuilder.h" #include "Engine/CSG/CSGBuilder.h"
#include "Engine/Engine/CommandLine.h" #include "Engine/Engine/CommandLine.h"
#include "Engine/Renderer/ProbesRenderer.h" #include "Engine/Renderer/ProbesRenderer.h"
#include "Engine/Animations/Graph/AnimGraph.h" #include "Engine/Animations/Graph/AnimGraph.h"
#include "Engine/Core/ObjectsRemovalService.h" #include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Level/Prefabs/Prefab.h"
#include "Engine/Serialization/JsonTools.h"
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions; ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
@@ -592,6 +595,7 @@ bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScript
void ManagedEditor::WipeOutLeftoverSceneObjects() void ManagedEditor::WipeOutLeftoverSceneObjects()
{ {
PROFILE_CPU();
Array<ScriptingObject*> objects = Scripting::GetObjects(); Array<ScriptingObject*> objects = Scripting::GetObjects();
bool removedAny = false; bool removedAny = false;
for (ScriptingObject* object : objects) for (ScriptingObject* object : objects)
@@ -613,6 +617,21 @@ void ManagedEditor::WipeOutLeftoverSceneObjects()
ObjectsRemovalService::Flush(); ObjectsRemovalService::Flush();
} }
void ManagedEditor::GetPrefabNestedObject(const Guid& prefabId, const Guid& prefabObjectId, Guid& outPrefabId, Guid& outPrefabObjectId)
{
outPrefabId = Guid::Empty;
outPrefabObjectId = Guid::Empty;
const auto prefab = Content::Load<Prefab>(prefabId);
if (!prefab)
return;
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(prefabObjectId);
if (!prefabObjectDataPtr)
return;
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
JsonTools::GetGuidIfValid(outPrefabId, prefabObjectData, "PrefabID");
JsonTools::GetGuidIfValid(outPrefabObjectId, prefabObjectData, "PrefabObjectID");
}
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly) void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
{ {
ASSERT(!HasManagedInstance()); ASSERT(!HasManagedInstance());

View File

@@ -259,6 +259,7 @@ public:
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals(); API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local); API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects(); API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects();
API_FUNCTION(Internal) static void GetPrefabNestedObject(API_PARAM(Ref) const Guid& prefabId, API_PARAM(Ref) const Guid& prefabObjectId, API_PARAM(Out) Guid& outPrefabId, API_PARAM(Out) Guid& outPrefabObjectId);
private: private:
void OnEditorAssemblyLoaded(MAssembly* assembly); void OnEditorAssemblyLoaded(MAssembly* assembly);

View File

@@ -21,6 +21,7 @@ namespace FlaxEditor.Modules
private bool _enableEvents; private bool _enableEvents;
private bool _isDuringFastSetup; private bool _isDuringFastSetup;
private bool _rebuildFlag; private bool _rebuildFlag;
private bool _rebuildInitFlag;
private int _itemsCreated; private int _itemsCreated;
private int _itemsDeleted; private int _itemsDeleted;
private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>(); private readonly HashSet<MainContentTreeNode> _dirtyNodes = new HashSet<MainContentTreeNode>();
@@ -61,7 +62,7 @@ namespace FlaxEditor.Modules
public event Action WorkspaceModified; public event Action WorkspaceModified;
/// <summary> /// <summary>
/// Occurs when workspace has will be rebuilt. /// Occurs when workspace will be rebuilt.
/// </summary> /// </summary>
public event Action WorkspaceRebuilding; public event Action WorkspaceRebuilding;
@@ -88,6 +89,9 @@ namespace FlaxEditor.Modules
// Register AssetItems serialization helper (serialize ref ID only) // Register AssetItems serialization helper (serialize ref ID only)
FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter()); FlaxEngine.Json.JsonSerializer.Settings.Converters.Add(new AssetItemConverter());
ScriptsBuilder.ScriptsReload += OnScriptsReload;
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
} }
private void OnContentAssetDisposing(Asset asset) private void OnContentAssetDisposing(Asset asset)
@@ -817,6 +821,7 @@ namespace FlaxEditor.Modules
Profiler.BeginEvent("ContentDatabase.Rebuild"); Profiler.BeginEvent("ContentDatabase.Rebuild");
var startTime = Platform.TimeSeconds; var startTime = Platform.TimeSeconds;
_rebuildFlag = false; _rebuildFlag = false;
_rebuildInitFlag = false;
_enableEvents = false; _enableEvents = false;
// Load all folders // Load all folders
@@ -1230,8 +1235,6 @@ namespace FlaxEditor.Modules
LoadProjects(Game.Project); LoadProjects(Game.Project);
} }
RebuildInternal();
Editor.ContentImporting.ImportFileEnd += (obj, failed) => Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
{ {
var path = obj.ResultUrl; var path = obj.ResultUrl;
@@ -1239,6 +1242,15 @@ namespace FlaxEditor.Modules
FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path)); FlaxEngine.Scripting.InvokeOnUpdate(() => OnImportFileDone(path));
}; };
_enableEvents = true; _enableEvents = true;
_rebuildInitFlag = true;
}
/// <inheritdoc />
public override void OnEndInit()
{
// Handle init when project was loaded without scripts loading ()
if (_rebuildInitFlag)
RebuildInternal();
} }
private void OnImportFileDone(string path) private void OnImportFileDone(string path)
@@ -1313,6 +1325,52 @@ namespace FlaxEditor.Modules
} }
} }
private void OnScriptsReload()
{
var enabledEvents = _enableEvents;
_enableEvents = false;
_isDuringFastSetup = true;
var startItems = _itemsCreated;
foreach (var project in Projects)
{
if (project.Content != null)
{
//Dispose(project.Content.Folder);
for (int i = 0; i < project.Content.Folder.Children.Count; i++)
{
Dispose(project.Content.Folder.Children[i]);
i--;
}
}
if (project.Source != null)
{
//Dispose(project.Source.Folder);
for (int i = 0; i < project.Source.Folder.Children.Count; i++)
{
Dispose(project.Source.Folder.Children[i]);
i--;
}
}
}
List<ContentProxy> removeProxies = new List<ContentProxy>();
foreach (var proxy in Editor.Instance.ContentDatabase.Proxy)
{
if (proxy.GetType().IsCollectible)
removeProxies.Add(proxy);
}
foreach (var proxy in removeProxies)
RemoveProxy(proxy, false);
_isDuringFastSetup = false;
_enableEvents = enabledEvents;
}
private void OnScriptsReloadEnd()
{
RebuildInternal();
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnUpdate() public override void OnUpdate()
{ {
@@ -1340,6 +1398,8 @@ namespace FlaxEditor.Modules
public override void OnExit() public override void OnExit()
{ {
FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing; FlaxEngine.Content.AssetDisposing -= OnContentAssetDisposing;
ScriptsBuilder.ScriptsReload -= OnScriptsReload;
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
// Disable events // Disable events
_enableEvents = false; _enableEvents = false;

View File

@@ -391,6 +391,20 @@ namespace FlaxEditor.Modules
public override void OnInit() public override void OnInit()
{ {
ImportFileEntry.RegisterDefaultTypes(); ImportFileEntry.RegisterDefaultTypes();
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
}
private void OnScriptsReloadBegin()
{
// Remove import file types from scripting assemblies
List<string> removeFileTypes = new List<string>();
foreach (var pair in ImportFileEntry.FileTypes)
{
if (pair.Value.Method.IsCollectible || (pair.Value.Target != null && pair.Value.Target.GetType().IsCollectible))
removeFileTypes.Add(pair.Key);
}
foreach (var fileType in removeFileTypes)
ImportFileEntry.FileTypes.Remove(fileType);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -451,6 +465,7 @@ namespace FlaxEditor.Modules
/// <inheritdoc /> /// <inheritdoc />
public override void OnExit() public override void OnExit()
{ {
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
EndWorker(); EndWorker();
} }
} }

View File

@@ -105,6 +105,33 @@ namespace FlaxEditor.Modules
Editor.Windows.ContentWin.NewItem(proxy, actor, contentItem => OnPrefabCreated(contentItem, actor, prefabWindow), actor.Name, rename); Editor.Windows.ContentWin.NewItem(proxy, actor, contentItem => OnPrefabCreated(contentItem, actor, prefabWindow), actor.Name, rename);
} }
/// <summary>
/// Opens a prefab editor window.
/// </summary>
public void OpenPrefab(ActorNode actorNode)
{
if (actorNode != null)
OpenPrefab(actorNode.Actor.PrefabID);
}
/// <summary>
/// Opens a prefab editor window.
/// </summary>
public void OpenPrefab(Guid prefabID = default)
{
if (prefabID == Guid.Empty)
{
var selection = Editor.SceneEditing.Selection.Where(x => x is ActorNode actorNode && actorNode.HasPrefabLink).ToList().BuildNodesParents();
if (selection.Count == 0 || !((ActorNode)selection[0]).Actor.HasPrefabLink)
return;
prefabID = ((ActorNode)selection[0]).Actor.PrefabID;
}
var item = Editor.ContentDatabase.Find(prefabID);
if (item != null)
Editor.ContentEditing.Open(item);
}
private void OnPrefabCreated(ContentItem contentItem, Actor actor, Windows.Assets.PrefabWindow prefabWindow) private void OnPrefabCreated(ContentItem contentItem, Actor actor, Windows.Assets.PrefabWindow prefabWindow)
{ {
if (contentItem is PrefabItem prefabItem) if (contentItem is PrefabItem prefabItem)

View File

@@ -58,7 +58,7 @@ namespace FlaxEditor.Modules
: base(editor) : base(editor)
{ {
// After editor cache but before the windows // After editor cache but before the windows
InitOrder = -900; InitOrder = -800;
} }
/// <summary> /// <summary>

View File

@@ -160,7 +160,7 @@ namespace FlaxEditor.Modules
internal UIModule(Editor editor) internal UIModule(Editor editor)
: base(editor) : base(editor)
{ {
InitOrder = -90; InitOrder = -70;
VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface"); VisjectSurfaceBackground = FlaxEngine.Content.LoadAsyncInternal<Texture>("Editor/VisjectSurface");
ColorValueBox.ShowPickColorDialog += ShowPickColorDialog; ColorValueBox.ShowPickColorDialog += ShowPickColorDialog;
} }

View File

@@ -5,10 +5,12 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Text; 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;
@@ -39,6 +41,7 @@ namespace FlaxEditor.Modules
public DockState DockState; public DockState DockState;
public DockPanel DockedTo; public DockPanel DockedTo;
public int DockedTabIndex;
public float? SplitterValue = null; public float? SplitterValue = null;
public bool SelectOnShow = false; public bool SelectOnShow = false;
@@ -48,6 +51,8 @@ namespace FlaxEditor.Modules
public Float2 FloatSize; public Float2 FloatSize;
public Float2 FloatPosition; public Float2 FloatPosition;
public Guid AssetItemID;
// Constructor, to allow for default values // Constructor, to allow for default values
public WindowRestoreData() public WindowRestoreData()
{ {
@@ -805,43 +810,64 @@ namespace FlaxEditor.Modules
Level.SceneSaving += OnSceneSaving; Level.SceneSaving += OnSceneSaving;
Level.SceneUnloaded += OnSceneUnloaded; Level.SceneUnloaded += OnSceneUnloaded;
Level.SceneUnloading += OnSceneUnloading; Level.SceneUnloading += OnSceneUnloading;
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd; Editor.ContentDatabase.WorkspaceRebuilt += OnWorkspaceRebuilt;
Editor.StateMachine.StateChanged += OnEditorStateChanged; Editor.StateMachine.StateChanged += OnEditorStateChanged;
} }
internal void AddToRestore(AssetEditorWindow win)
{
AddToRestore(win, win.GetType(), new WindowRestoreData
{
AssetItemID = win.Item.ID,
});
}
internal void AddToRestore(CustomEditorWindow win) internal void AddToRestore(CustomEditorWindow win)
{ {
var type = win.GetType(); AddToRestore(win.Window, win.GetType(), new WindowRestoreData());
}
private void AddToRestore(EditorWindow win, Type type, WindowRestoreData winData)
{
// Validate if can restore type // Validate if can restore type
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (constructor == null || type.IsGenericType) if (constructor == null || type.IsGenericType)
return; return;
var winData = new WindowRestoreData(); var panel = win.ParentDockPanel;
var panel = win.Window.ParentDockPanel;
// Ensure that this window is only selected following recompilation // Ensure that this window is only selected following recompilation
// if it was the active tab in its dock panel. Otherwise, there is a // if it was the active tab in its dock panel. Otherwise, there is a
// risk of interrupting the user's workflow by potentially selecting // risk of interrupting the user's workflow by potentially selecting
// background tabs. // background tabs.
winData.SelectOnShow = panel.SelectedTab == win.Window; var window = win.RootWindow.Window;
if (panel is FloatWindowDockPanel) winData.SelectOnShow = panel.SelectedTab == win;
winData.DockedTabIndex = 0;
if (panel is FloatWindowDockPanel && window != null && panel.TabsCount == 1)
{ {
winData.DockState = DockState.Float; winData.DockState = DockState.Float;
var window = win.Window.RootWindow.Window;
winData.FloatPosition = window.Position; winData.FloatPosition = window.Position;
winData.FloatSize = window.ClientSize; winData.FloatSize = window.ClientSize;
winData.Maximize = window.IsMaximized; winData.Maximize = window.IsMaximized;
winData.Minimize = window.IsMinimized; winData.Minimize = window.IsMinimized;
winData.DockedTo = panel;
} }
else else
{ {
for (int i = 0; i < panel.Tabs.Count; i++)
{
if (panel.Tabs[i] == win)
{
winData.DockedTabIndex = i;
break;
}
}
if (panel.TabsCount > 1) if (panel.TabsCount > 1)
{ {
winData.DockState = DockState.DockFill; winData.DockState = DockState.DockFill;
winData.DockedTo = panel; winData.DockedTo = panel;
}else }
else
{ {
winData.DockState = panel.TryGetDockState(out var splitterValue); winData.DockState = panel.TryGetDockState(out var splitterValue);
winData.DockedTo = panel.ParentDockPanel; winData.DockedTo = panel.ParentDockPanel;
@@ -853,38 +879,93 @@ namespace FlaxEditor.Modules
_restoreWindows.Add(winData); _restoreWindows.Add(winData);
} }
private void OnScriptsReloadEnd() private void OnWorkspaceRebuilt()
{ {
for (int i = 0; i < _restoreWindows.Count; i++) // Go in reverse order to create floating Prefab windows first before docked windows
for (int i = _restoreWindows.Count - 1; i >= 0; i--)
{ {
var winData = _restoreWindows[i]; var winData = _restoreWindows[i];
try try
{ {
var assembly = Utils.GetAssemblyByName(winData.AssemblyName); var assembly = Utils.GetAssemblyByName(winData.AssemblyName);
if (assembly != null) if (assembly == null)
continue;
var type = assembly.GetType(winData.TypeName);
if (type == null)
continue;
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
{ {
var type = assembly.GetType(winData.TypeName); var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
if (type != null) var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
if (winData.DockState == DockState.Float)
{ {
var win = (CustomEditorWindow)Activator.CreateInstance(type); var window = win.RootWindow.Window;
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue); window.Position = winData.FloatPosition;
if (winData.DockState == DockState.Float) if (winData.Maximize)
{ {
var window = win.Window.RootWindow.Window; window.Maximize();
window.Position = winData.FloatPosition; }
if (winData.Maximize) else if (winData.Minimize)
{ {
window.Maximize(); window.Minimize();
} }
else if (winData.Minimize) else
{ {
window.Minimize(); window.ClientSize = winData.FloatSize;
} }
else
{ // Update panel reference in other windows docked to this panel
window.ClientSize = winData.FloatSize; foreach (ref var otherData in CollectionsMarshal.AsSpan(_restoreWindows))
} {
if (otherData.DockedTo == winData.DockedTo)
otherData.DockedTo = win.ParentDockPanel;
}
}
var panel = win.ParentDockPanel;
int currentTabIndex = 0;
for (int pi = 0; pi < panel.TabsCount; pi++)
{
if (panel.Tabs[pi] == win)
{
currentTabIndex = pi;
break;
}
}
while (currentTabIndex > winData.DockedTabIndex)
{
win.ParentDockPanel.MoveTabLeft(currentTabIndex);
currentTabIndex--;
}
while (currentTabIndex < winData.DockedTabIndex)
{
win.ParentDockPanel.MoveTabRight(currentTabIndex);
currentTabIndex++;
}
}
else
{
var win = (CustomEditorWindow)Activator.CreateInstance(type);
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
if (winData.DockState == DockState.Float)
{
var window = win.Window.RootWindow.Window;
window.Position = winData.FloatPosition;
if (winData.Maximize)
{
window.Maximize();
}
else if (winData.Minimize)
{
window.Minimize();
}
else
{
window.ClientSize = winData.FloatSize;
} }
} }
} }
@@ -895,6 +976,11 @@ namespace FlaxEditor.Modules
Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName)); Editor.LogWarning(string.Format("Failed to restore window {0} (assembly: {1})", winData.TypeName, winData.AssemblyName));
} }
} }
// Restored windows stole the focus from Editor
if (_restoreWindows.Count > 0)
Editor.Instance.Windows.MainWindow.Focus();
_restoreWindows.Clear(); _restoreWindows.Clear();
} }
@@ -1050,7 +1136,7 @@ namespace FlaxEditor.Modules
Level.SceneSaving -= OnSceneSaving; Level.SceneSaving -= OnSceneSaving;
Level.SceneUnloaded -= OnSceneUnloaded; Level.SceneUnloaded -= OnSceneUnloaded;
Level.SceneUnloading -= OnSceneUnloading; Level.SceneUnloading -= OnSceneUnloading;
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd; Editor.ContentDatabase.WorkspaceRebuilt -= OnWorkspaceRebuilt;
Editor.StateMachine.StateChanged -= OnEditorStateChanged; Editor.StateMachine.StateChanged -= OnEditorStateChanged;
// Close main window // Close main window

View File

@@ -8,6 +8,7 @@ using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements; using FlaxEditor.CustomEditors.Elements;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using static FlaxEditor.Viewport.EditorViewport;
namespace FlaxEditor.Options namespace FlaxEditor.Options
{ {
@@ -18,7 +19,7 @@ namespace FlaxEditor.Options
[HideInEditor] [HideInEditor]
[TypeConverter(typeof(InputBindingConverter))] [TypeConverter(typeof(InputBindingConverter))]
[CustomEditor(typeof(InputBindingEditor))] [CustomEditor(typeof(InputBindingEditor))]
public struct InputBinding public struct InputBinding : IEquatable<InputBinding>
{ {
/// <summary> /// <summary>
/// The key to bind. /// The key to bind.
@@ -251,6 +252,40 @@ namespace FlaxEditor.Options
} }
return result; return result;
} }
/// <inheritdoc />
public bool Equals(InputBinding other)
{
return Key == other.Key && Modifier1 == other.Modifier1 && Modifier2 == other.Modifier2;
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is InputBinding other && Equals(other);
}
/// <inheritdoc />
public override int GetHashCode()
{
return HashCode.Combine((int)Key, (int)Modifier1, (int)Modifier2);
}
/// <summary>
/// Compares two values.
/// </summary>
public static bool operator ==(InputBinding left, InputBinding right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two values.
/// </summary>
public static bool operator !=(InputBinding left, InputBinding right)
{
return !left.Equals(right);
}
} }
class InputBindingConverter : TypeConverter class InputBindingConverter : TypeConverter
@@ -522,5 +557,27 @@ namespace FlaxEditor.Options
return false; return false;
} }
/// <summary>
/// Invokes a specific binding.
/// </summary>
/// <param name="editor">The editor instance.</param>
/// <param name="binding">The binding to execute.</param>
/// <returns>True if event has been handled, otherwise false.</returns>
public bool Invoke(Editor editor, InputBinding binding)
{
if (binding == new InputBinding())
return false;
var options = editor.Options.Options.Input;
for (int i = 0; i < Bindings.Count; i++)
{
if (Bindings[i].Binder(options) == binding)
{
Bindings[i].Callback();
return true;
}
}
return false;
}
} }
} }

View File

@@ -7,6 +7,32 @@ using FlaxEngine;
namespace FlaxEditor.Options namespace FlaxEditor.Options
{ {
/// <summary>
/// Action to perform when a Scene Node receive a double mouse left click.
/// </summary>
public enum SceneNodeDoubleClick
{
/// <summary>
/// Toggles expand/state of the node.
/// </summary>
Expand,
/// <summary>
/// Rename the node.
/// </summary>
RenameActor,
/// <summary>
/// Focus the object in the viewport.
/// </summary>
FocusActor,
/// <summary>
/// If possible, open the scene node in an associated Editor (eg. Prefab Editor).
/// </summary>
OpenPrefab,
}
/// <summary> /// <summary>
/// Input editor options data container. /// Input editor options data container.
/// </summary> /// </summary>
@@ -344,6 +370,10 @@ namespace FlaxEditor.Options
[EditorDisplay("Interface"), EditorOrder(2020)] [EditorDisplay("Interface"), EditorOrder(2020)]
public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift); public InputBinding PreviousTab = new InputBinding(KeyboardKeys.Tab, KeyboardKeys.Control, KeyboardKeys.Shift);
[DefaultValue(SceneNodeDoubleClick.Expand)]
[EditorDisplay("Interface"), EditorOrder(2030)]
public SceneNodeDoubleClick DoubleClickSceneNode = SceneNodeDoubleClick.Expand;
#endregion #endregion
} }
} }

View File

@@ -157,7 +157,7 @@ namespace FlaxEditor.Options
/// <summary> /// <summary>
/// Focus the Game Window. On play mode end restore focus to the previous window. /// Focus the Game Window. On play mode end restore focus to the previous window.
/// </summary> /// </summary>
GameWindowThenRestore, GameWindowThenRestore,
} }
/// <summary> /// <summary>
@@ -379,6 +379,22 @@ namespace FlaxEditor.Options
} }
} }
/// <summary>
/// Gets or sets the output log text color for warnings
/// </summary>
[DefaultValue(typeof(Color), "1,1,0,1")]
[EditorDisplay("Output Log", "Warning Color"), EditorOrder(446), Tooltip("The output log text color for warnings.")]
public Color OutputLogWarningTextColor { get; set; } = Color.Yellow;
/// <summary>
/// Gets or sets the output log text color for errors
/// </summary>
[DefaultValue(typeof(Color), "1,0,0,1")]
[EditorDisplay("Output Log", "Error Color"), EditorOrder(445), Tooltip("The output log text color for errors.")]
public Color OutputLogErrorTextColor { get; set; } = Color.Red;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether auto-focus output log window on code compilation error. /// Gets or sets a value indicating whether auto-focus output log window on code compilation error.
/// </summary> /// </summary>

View File

@@ -8,6 +8,7 @@ using FlaxEditor.Content;
using FlaxEditor.GUI; using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag; using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tree; using FlaxEditor.GUI.Tree;
using FlaxEditor.Options;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Utilities; using FlaxEditor.Utilities;
using FlaxEditor.Windows; using FlaxEditor.Windows;
@@ -15,7 +16,6 @@ using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
using Object = FlaxEngine.Object;
namespace FlaxEditor.SceneGraph.GUI namespace FlaxEditor.SceneGraph.GUI
{ {
@@ -393,7 +393,7 @@ namespace FlaxEditor.SceneGraph.GUI
/// <summary> /// <summary>
/// Starts the actor renaming action. /// Starts the actor renaming action.
/// </summary> /// </summary>
public void StartRenaming(EditorWindow window, Panel treePanel = null) public void StartRenaming(EditorWindow window = null, Panel treePanel = null)
{ {
// Block renaming during scripts reload // Block renaming during scripts reload
if (Editor.Instance.ProgressReporting.CompileScripts.IsActive) if (Editor.Instance.ProgressReporting.CompileScripts.IsActive)
@@ -461,6 +461,30 @@ namespace FlaxEditor.SceneGraph.GUI
} }
} }
/// <inheritdoc />
protected override bool OnMouseDoubleClickHeader(ref Float2 location, MouseButton button)
{
if (button == MouseButton.Left)
{
var sceneContext = this.GetSceneContext();
switch (Editor.Instance.Options.Options.Input.DoubleClickSceneNode)
{
case SceneNodeDoubleClick.RenameActor:
sceneContext.RenameSelection();
return true;
case SceneNodeDoubleClick.FocusActor:
sceneContext.FocusSelection();
return true;
case SceneNodeDoubleClick.OpenPrefab:
Editor.Instance.Prefabs.OpenPrefab(ActorNode);
return true;
case SceneNodeDoubleClick.Expand:
default: break;
}
}
return base.OnMouseDoubleClickHeader(ref location, button);
}
/// <inheritdoc /> /// <inheritdoc />
protected override DragDropEffect OnDragEnterHeader(DragData data) protected override DragDropEffect OnDragEnterHeader(DragData data)
{ {

View File

@@ -469,6 +469,7 @@ namespace FlaxEditor.SceneGraph
{ {
ChildNodes[i].OnDispose(); ChildNodes[i].OnDispose();
} }
ChildNodes.Clear();
SceneGraphFactory.Nodes.Remove(ID); SceneGraphFactory.Nodes.Remove(ID);
} }

View File

@@ -161,6 +161,8 @@ namespace FlaxEditor.Surface
private void OnScriptsReloadBegin() private void OnScriptsReloadBegin()
{ {
_nodesCache.Clear();
// Check if any of the nodes comes from the game scripts - those can be reloaded at runtime so prevent crashes // Check if any of the nodes comes from the game scripts - those can be reloaded at runtime so prevent crashes
bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts; bool hasTypeFromGameScripts = Editor.Instance.CodeEditing.AnimGraphNodes.HasTypeFromGameScripts;

View File

@@ -1182,9 +1182,9 @@ namespace FlaxEditor.Surface.Archetypes
} }
/// <inheritdoc /> /// <inheritdoc />
public override void DrawEditorBackground(ref Rectangle rect) public override void DrawEditorGrid(ref Rectangle rect)
{ {
base.DrawEditorBackground(ref rect); base.DrawEditorGrid(ref rect);
// Draw triangulated multi blend space // Draw triangulated multi blend space
var style = Style.Current; var style = Style.Current;
@@ -1195,15 +1195,8 @@ namespace FlaxEditor.Surface.Archetypes
else else
Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f)); Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f));
Render2D.DrawTriangles(_triangles, style.Foreground); Render2D.DrawTriangles(_triangles, style.Foreground);
}
/// <inheritdoc />
public override void DrawEditorGrid(ref Rectangle rect)
{
base.DrawEditorGrid(ref rect);
// Highlight selected blend point // Highlight selected blend point
var style = Style.Current;
var selectedIndex = _selectedAnimation.SelectedIndex; var selectedIndex = _selectedAnimation.SelectedIndex;
if (selectedIndex != -1 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver)) if (selectedIndex != -1 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver))
{ {

View File

@@ -87,11 +87,17 @@ namespace FlaxEditor.Surface.Archetypes
private class GradientStop : Control private class GradientStop : Control
{ {
private bool _isMoving; private bool _isMoving;
private float _movedToTime = float.MaxValue;
private Float2 _startMovePos; private Float2 _startMovePos;
public ColorGradientNode Node; public ColorGradientNode Node;
public Color Color; public Color Color;
public void UpdateLocation(float time)
{
Location = Node._gradient.BottomLeft + new Float2(time * Node._gradient.Width - Width * 0.5f, 0.0f);
}
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {
@@ -118,6 +124,7 @@ namespace FlaxEditor.Surface.Archetypes
if (button == MouseButton.Left) if (button == MouseButton.Left)
{ {
Node.Select(this); Node.Select(this);
_movedToTime = float.MaxValue;
_isMoving = true; _isMoving = true;
_startMovePos = location; _startMovePos = location;
StartMouseCapture(); StartMouseCapture();
@@ -133,6 +140,12 @@ namespace FlaxEditor.Surface.Archetypes
if (button == MouseButton.Left && _isMoving) if (button == MouseButton.Left && _isMoving)
{ {
_isMoving = false; _isMoving = false;
if (_movedToTime < float.MaxValue)
{
int index = Node._stops.IndexOf(this);
Node.SetStopTime(index, _movedToTime);
_movedToTime = float.MaxValue;
}
EndMouseCapture(); EndMouseCapture();
} }
@@ -159,9 +172,10 @@ namespace FlaxEditor.Surface.Archetypes
if (_isMoving && Float2.DistanceSquared(ref location, ref _startMovePos) > 25.0f) if (_isMoving && Float2.DistanceSquared(ref location, ref _startMovePos) > 25.0f)
{ {
_startMovePos = Float2.Minimum; _startMovePos = Float2.Minimum;
var index = Node._stops.IndexOf(this); int index = Node._stops.IndexOf(this);
var time = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width; _movedToTime = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width;
Node.SetStopTime(index, time); _movedToTime = Node.ClampStopTime(index, _movedToTime);
UpdateLocation(_movedToTime);
} }
base.OnMouseMove(location); base.OnMouseMove(location);
@@ -171,6 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
public override void OnEndMouseCapture() public override void OnEndMouseCapture()
{ {
_isMoving = false; _isMoving = false;
_movedToTime = float.MaxValue;
base.OnEndMouseCapture(); base.OnEndMouseCapture();
} }
@@ -223,6 +238,7 @@ namespace FlaxEditor.Surface.Archetypes
Parent = this Parent = this
}; };
_timeValue.ValueChanged += OnTimeValueChanged; _timeValue.ValueChanged += OnTimeValueChanged;
_timeValue.SlidingEnd += OnTimeValueChanged;
_colorValue = new ColorValueBox(Color.Black, _timeValue.Right + 4.0f, controlsLevel) _colorValue = new ColorValueBox(Color.Black, _timeValue.Right + 4.0f, controlsLevel)
{ {
@@ -301,8 +317,16 @@ namespace FlaxEditor.Surface.Archetypes
private void OnTimeValueChanged() private void OnTimeValueChanged()
{ {
var time = _timeValue.Value;
var index = _stops.IndexOf(_selected); var index = _stops.IndexOf(_selected);
SetStopTime(index, _timeValue.Value); if (_timeValue.IsSliding)
{
// Preview-only while sliding
time = ClampStopTime(index, time);
_selected.UpdateLocation(time);
return;
}
SetStopTime(index, time);
} }
private void OnColorValueChanged() private void OnColorValueChanged()
@@ -346,7 +370,7 @@ namespace FlaxEditor.Surface.Archetypes
UpdateStops(); UpdateStops();
} }
private void SetStopTime(int index, float time) private float ClampStopTime(int index, float time)
{ {
time = Mathf.Saturate(time); time = Mathf.Saturate(time);
if (index != 0) if (index != 0)
@@ -357,6 +381,12 @@ namespace FlaxEditor.Surface.Archetypes
{ {
time = Mathf.Min(time, (float)Values[1 + index * 2 + 2]); time = Mathf.Min(time, (float)Values[1 + index * 2 + 2]);
} }
return time;
}
private void SetStopTime(int index, float time)
{
time = ClampStopTime(index, time);
SetValue(1 + index * 2, time); SetValue(1 + index * 2, time);
} }
@@ -395,7 +425,7 @@ namespace FlaxEditor.Surface.Archetypes
{ {
var stop = _stops[i]; var stop = _stops[i];
var time = (float)Values[i * 2 + 1]; var time = (float)Values[i * 2 + 1];
stop.Location = _gradient.BottomLeft + new Float2(time * _gradient.Width - stop.Width * 0.5f, 0.0f); stop.UpdateLocation(time);
stop.Color = (Color)Values[i * 2 + 2]; stop.Color = (Color)Values[i * 2 + 2];
stop.TooltipText = stop.Color + " at " + time; stop.TooltipText = stop.Color + " at " + time;
} }

View File

@@ -24,6 +24,7 @@ namespace FlaxEditor.Surface
public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo) public BehaviorTreeSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
: base(owner, onSave, undo, CreateStyle()) : base(owner, onSave, undo, CreateStyle())
{ {
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
} }
private static SurfaceStyle CreateStyle() private static SurfaceStyle CreateStyle()
@@ -35,6 +36,11 @@ namespace FlaxEditor.Surface
return style; return style;
} }
private void OnScriptsReloadBegin()
{
_nodesCache.Clear();
}
private static void DrawBox(Box box) private static void DrawBox(Box box)
{ {
var rect = new Rectangle(Float2.Zero, box.Size); var rect = new Rectangle(Float2.Zero, box.Size);
@@ -186,6 +192,7 @@ namespace FlaxEditor.Surface
{ {
if (IsDisposing) if (IsDisposing)
return; return;
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
_nodesCache.Wait(); _nodesCache.Wait();
base.OnDestroy(); base.OnDestroy();

View File

@@ -415,6 +415,15 @@ namespace FlaxEditor.Surface
// Init drag handlers // Init drag handlers
DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem)); DragHandlers.Add(_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem));
DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter)); DragHandlers.Add(_dragParameters = new DragNames<DragDropEventArgs>(SurfaceParameter.DragPrefix, ValidateDragParameter));
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
}
private void OnScriptsReloadBegin()
{
_activeVisjectCM = null;
_cmPrimaryMenu?.Dispose();
_cmPrimaryMenu = null;
} }
/// <summary> /// <summary>
@@ -1023,6 +1032,8 @@ namespace FlaxEditor.Surface
_activeVisjectCM = null; _activeVisjectCM = null;
_cmPrimaryMenu?.Dispose(); _cmPrimaryMenu?.Dispose();
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
base.OnDestroy(); base.OnDestroy();
} }
} }

View File

@@ -62,6 +62,12 @@ namespace FlaxEditor.Surface
{ {
_supportsImplicitCastFromObjectToBoolean = true; _supportsImplicitCastFromObjectToBoolean = true;
DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor)); DragHandlers.Add(_dragActors = new DragActors(ValidateDragActor));
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
}
private void OnScriptsReloadBegin()
{
_nodesCache.Clear();
} }
private bool ValidateDragActor(ActorNode actor) private bool ValidateDragActor(ActorNode actor)
@@ -631,6 +637,7 @@ namespace FlaxEditor.Surface
{ {
if (IsDisposing) if (IsDisposing)
return; return;
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
_nodesCache.Wait(); _nodesCache.Wait();
base.OnDestroy(); base.OnDestroy();

View File

@@ -23,7 +23,7 @@ namespace FlaxEditor.Actions
public Guid PrefabID; public Guid PrefabID;
public Guid PrefabObjectID; public Guid PrefabObjectID;
public unsafe Item(SceneObject obj, List<Item> nestedPrefabLinks) public Item(SceneObject obj, List<Item> nestedPrefabLinks)
{ {
ID = obj.ID; ID = obj.ID;
PrefabID = obj.PrefabID; PrefabID = obj.PrefabID;
@@ -33,8 +33,7 @@ namespace FlaxEditor.Actions
// Check if this object comes from another nested prefab (to break link only from the top-level prefab) // Check if this object comes from another nested prefab (to break link only from the top-level prefab)
Item nested; Item nested;
nested.ID = ID; nested.ID = ID;
fixed (Item* i = &this) Editor.GetPrefabNestedObject(ref PrefabID, ref PrefabObjectID, out nested.PrefabID, out nested.PrefabObjectID);
Editor.Internal_GetPrefabNestedObject(new IntPtr(&i->PrefabID), new IntPtr(&i->PrefabObjectID), new IntPtr(&nested.PrefabID), new IntPtr(&nested.PrefabObjectID));
if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty) if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty)
nestedPrefabLinks.Add(nested); nestedPrefabLinks.Add(nested);
} }

View File

@@ -42,7 +42,7 @@ namespace FlaxEditor
/// </summary> /// </summary>
/// <typeparam name="TData">The type of the data. Must have <see cref="SerializableAttribute"/>.</typeparam> /// <typeparam name="TData">The type of the data. Must have <see cref="SerializableAttribute"/>.</typeparam>
/// <seealso cref="FlaxEditor.IUndoAction" /> /// <seealso cref="FlaxEditor.IUndoAction" />
[Serializable] [Serializable, HideInEditor]
public abstract class UndoActionBase<TData> : IUndoAction where TData : struct public abstract class UndoActionBase<TData> : IUndoAction where TData : struct
{ {
/// <summary> /// <summary>

View File

@@ -5,7 +5,7 @@ namespace FlaxEditor.Utilities;
/// <summary> /// <summary>
/// Units display utilities for Editor. /// Units display utilities for Editor.
/// </summary> /// </summary>
public class Units public static class Units
{ {
/// <summary> /// <summary>
/// Factor of units per meter. /// Factor of units per meter.

View File

@@ -236,19 +236,19 @@ namespace FlaxEditor.Utilities
/// <summary> /// <summary>
/// The time/value axes tick steps for editors with timeline. /// The time/value axes tick steps for editors with timeline.
/// </summary> /// </summary>
internal static readonly float[] CurveTickSteps = internal static readonly double[] CurveTickSteps =
{ {
0.0000001f, 0.0000005f, 0.000001f, 0.000005f, 0.00001f, 0.0000001, 0.0000005, 0.000001, 0.000005, 0.00001,
0.00005f, 0.0001f, 0.0005f, 0.001f, 0.005f, 0.00005, 0.0001, 0.0005, 0.001, 0.005,
0.01f, 0.05f, 0.1f, 0.5f, 1, 0.01, 0.05, 0.1, 0.5, 1,
5, 10, 50, 100, 500, 5, 10, 50, 100, 500,
1000, 5000, 10000, 50000, 100000, 1000, 5000, 10000, 50000, 100000,
500000, 1000000, 5000000, 10000000, 100000000 500000, 1000000, 5000000, 10000000, 100000000
}; };
internal delegate void DrawCurveTick(float tick, float strength); internal delegate void DrawCurveTick(decimal tick, double step, float strength);
internal static Int2 DrawCurveTicks(DrawCurveTick drawTick, float[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60) internal static Int2 DrawCurveTicks(DrawCurveTick drawTick, double[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60)
{ {
if (pixelRange <= Mathf.Epsilon || maxDistanceBetweenTicks <= minDistanceBetweenTicks) if (pixelRange <= Mathf.Epsilon || maxDistanceBetweenTicks <= minDistanceBetweenTicks)
return Int2.Zero; return Int2.Zero;
@@ -262,10 +262,10 @@ namespace FlaxEditor.Utilities
for (int i = tickSteps.Length - 1; i >= 0; i--) for (int i = tickSteps.Length - 1; i >= 0; i--)
{ {
// Calculate how far apart these modulo tick steps are spaced // Calculate how far apart these modulo tick steps are spaced
float tickSpacing = tickSteps[i] * pixelsInRange; var tickSpacing = tickSteps[i] * pixelsInRange;
// Calculate the strength of the tick markers based on the spacing // Calculate the strength of the tick markers based on the spacing
tickStrengths[i] = Mathf.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks)); tickStrengths[i] = (float)Mathd.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks));
// Beyond threshold the ticks don't get any bigger or fatter // Beyond threshold the ticks don't get any bigger or fatter
if (tickStrengths[i] >= 1) if (tickStrengths[i] >= 1)
@@ -283,7 +283,7 @@ namespace FlaxEditor.Utilities
// Draw all tick levels // Draw all tick levels
for (int level = 0; level < tickLevels; level++) for (int level = 0; level < tickLevels; level++)
{ {
float strength = tickStrengths[smallestTick + level]; var strength = tickStrengths[smallestTick + level];
if (strength <= Mathf.Epsilon) if (strength <= Mathf.Epsilon)
continue; continue;
@@ -291,20 +291,36 @@ namespace FlaxEditor.Utilities
int l = Mathf.Clamp(smallestTick + level, 0, tickSteps.Length - 2); int l = Mathf.Clamp(smallestTick + level, 0, tickSteps.Length - 2);
var lStep = tickSteps[l]; var lStep = tickSteps[l];
var lNextStep = tickSteps[l + 1]; var lNextStep = tickSteps[l + 1];
int startTick = Mathf.FloorToInt(min / lStep); var startTick = Mathd.FloorToInt(min / lStep);
int endTick = Mathf.CeilToInt(max / lStep); var endTick = Mathd.CeilToInt(max / lStep);
for (int i = startTick; i <= endTick; i++) for (var i = startTick; i <= endTick; i++)
{ {
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0)) if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
continue; continue;
var tick = i * lStep; var tick = (decimal)lStep * i;
drawTick(tick, strength); drawTick(tick, lStep, strength);
} }
} }
return new Int2(smallestTick, biggestTick); return new Int2(smallestTick, biggestTick);
} }
internal static float GetCurveGridSnap(double[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60)
{
double gridStep = 0; // No grid
float gridWeight = 0.0f;
DrawCurveTicks((decimal tick, double step, float strength) =>
{
// Find the smallest grid step that has meaningful strength (it's the most visible to the user)
if (strength > gridWeight && (step < gridStep || gridStep <= 0.0) && strength > 0.5f)
{
gridStep = Math.Abs(step);
gridWeight = strength;
}
}, tickSteps, ref tickStrengths, min, max, pixelRange, minDistanceBetweenTicks, maxDistanceBetweenTicks);
return (float)gridStep;
}
/// <summary> /// <summary>
/// Determines whether the specified path string contains any invalid character. /// Determines whether the specified path string contains any invalid character.
/// </summary> /// </summary>
@@ -1528,5 +1544,12 @@ namespace FlaxEditor.Utilities
} }
return path; return path;
} }
internal static ISceneContextWindow GetSceneContext(this Control c)
{
while (c != null && !(c is ISceneContextWindow))
c = c.Parent;
return c as ISceneContextWindow;
}
} }
} }

View File

@@ -5,10 +5,12 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Gizmo; using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Cameras; using FlaxEditor.Viewport.Cameras;
using FlaxEditor.Viewport.Previews; using FlaxEditor.Viewport.Previews;
using FlaxEditor.Viewport.Widgets;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -44,7 +46,7 @@ namespace FlaxEditor.Viewport
private sealed class PrefabUIEditorRoot : UIEditorRoot private sealed class PrefabUIEditorRoot : UIEditorRoot
{ {
private readonly PrefabWindowViewport _viewport; private readonly PrefabWindowViewport _viewport;
private bool UI => _viewport._hasUILinkedCached; private bool UI => _viewport.ShowUI;
public PrefabUIEditorRoot(PrefabWindowViewport viewport) public PrefabUIEditorRoot(PrefabWindowViewport viewport)
: base(true) : base(true)
@@ -67,8 +69,78 @@ namespace FlaxEditor.Viewport
private PrefabSpritesRenderer _spritesRenderer; private PrefabSpritesRenderer _spritesRenderer;
private IntPtr _tempDebugDrawContext; private IntPtr _tempDebugDrawContext;
private bool _hasUILinkedCached;
private PrefabUIEditorRoot _uiRoot; private PrefabUIEditorRoot _uiRoot;
private bool _showUI = false;
private ContextMenuButton _uiModeButton;
/// <summary>
/// Event fired when the UI Mode is toggled.
/// </summary>
public event Action<bool> UIModeToggled;
/// <summary>
/// set the initial UI mod
/// </summary>
/// <param name="value">the initial ShowUI value</param>
public void SetInitialUIMode(bool value)
{
ShowUI = value;
_uiModeButton.Checked = value;
}
/// <summary>
/// Whether to show the UI mode or not.
/// </summary>
public bool ShowUI
{
get => _showUI;
set
{
_showUI = value;
if (_showUI)
{
// UI widget
Gizmos.Active = null;
ViewportCamera = new UIEditorCamera { UIEditor = _uiRoot };
// Hide 3D visuals
ShowEditorPrimitives = false;
ShowDefaultSceneActors = false;
ShowDebugDraw = false;
// Show whole UI on startup
var canvas = (CanvasRootControl)_uiParentLink.Children.FirstOrDefault(x => x is CanvasRootControl);
if (canvas != null)
ViewportCamera.ShowActor(canvas.Canvas);
else if (Instance is UIControl)
ViewportCamera.ShowActor(Instance);
_uiRoot.Visible = true;
}
else
{
// Generic prefab
Gizmos.Active = TransformGizmo;
ViewportCamera = new FPSCamera();
_uiRoot.Visible = false;
}
// Update default components usage
bool defaultFeatures = !_showUI;
_disableInputUpdate = _showUI;
_spritesRenderer.Enabled = defaultFeatures;
SelectionOutline.Enabled = defaultFeatures;
_showDefaultSceneButton.Visible = defaultFeatures;
_cameraWidget.Visible = defaultFeatures;
_cameraButton.Visible = defaultFeatures;
_orthographicModeButton.Visible = defaultFeatures;
Task.Enabled = defaultFeatures;
UseAutomaticTaskManagement = defaultFeatures;
ShowDefaultSceneActors = defaultFeatures;
TintColor = defaultFeatures ? Color.White : Color.Transparent;
UIModeToggled?.Invoke(_showUI);
}
}
/// <summary> /// <summary>
/// Drag and drop handlers /// Drag and drop handlers
@@ -138,6 +210,11 @@ namespace FlaxEditor.Viewport
_uiRoot.IndexInParent = 0; // Move viewport down below other widgets in the viewport _uiRoot.IndexInParent = 0; // Move viewport down below other widgets in the viewport
_uiParentLink = _uiRoot.UIRoot; _uiParentLink = _uiRoot.UIRoot;
// UI mode buton
_uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", (button) => ShowUI = button.Checked);
_uiModeButton.AutoCheck = true;
_uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI;
EditorGizmoViewport.AddGizmoViewportWidgets(this, TransformGizmo); EditorGizmoViewport.AddGizmoViewportWidgets(this, TransformGizmo);
// Setup input actions // Setup input actions
@@ -146,58 +223,8 @@ namespace FlaxEditor.Viewport
SetUpdate(ref _update, OnUpdate); SetUpdate(ref _update, OnUpdate);
} }
/// <summary>
/// Updates the viewport's gizmos, especially to toggle between 3D and UI editing modes.
/// </summary>
internal void UpdateGizmoMode()
{
// Skip if gizmo mode was unmodified
if (_hasUILinked == _hasUILinkedCached)
return;
_hasUILinkedCached = _hasUILinked;
if (_hasUILinked)
{
// UI widget
Gizmos.Active = null;
ViewportCamera = new UIEditorCamera { UIEditor = _uiRoot };
// Hide 3D visuals
ShowEditorPrimitives = false;
ShowDefaultSceneActors = false;
ShowDebugDraw = false;
// Show whole UI on startup
var canvas = (CanvasRootControl)_uiParentLink.Children.FirstOrDefault(x => x is CanvasRootControl);
if (canvas != null)
ViewportCamera.ShowActor(canvas.Canvas);
else if (Instance is UIControl)
ViewportCamera.ShowActor(Instance);
}
else
{
// Generic prefab
Gizmos.Active = TransformGizmo;
ViewportCamera = new FPSCamera();
}
// Update default components usage
bool defaultFeatures = !_hasUILinked;
_disableInputUpdate = _hasUILinked;
_spritesRenderer.Enabled = defaultFeatures;
SelectionOutline.Enabled = defaultFeatures;
_showDefaultSceneButton.Visible = defaultFeatures;
_cameraWidget.Visible = defaultFeatures;
_cameraButton.Visible = defaultFeatures;
_orthographicModeButton.Visible = defaultFeatures;
Task.Enabled = defaultFeatures;
UseAutomaticTaskManagement = defaultFeatures;
TintColor = defaultFeatures ? Color.White : Color.Transparent;
}
private void OnUpdate(float deltaTime) private void OnUpdate(float deltaTime)
{ {
UpdateGizmoMode();
for (int i = 0; i < Gizmos.Count; i++) for (int i = 0; i < Gizmos.Count; i++)
{ {
Gizmos[i].Update(deltaTime); Gizmos[i].Update(deltaTime);

View File

@@ -58,6 +58,8 @@ namespace FlaxEditor.Windows.Assets
InputActions.Add(options => options.Save, Save); InputActions.Add(options => options.Save, Save);
UpdateTitle(); UpdateTitle();
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
} }
/// <summary> /// <summary>
@@ -151,6 +153,8 @@ namespace FlaxEditor.Windows.Assets
/// <inheritdoc /> /// <inheritdoc />
public override void OnDestroy() public override void OnDestroy()
{ {
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
if (_item != null) if (_item != null)
{ {
// Ensure to remove linkage to the item // Ensure to remove linkage to the item
@@ -160,6 +164,15 @@ namespace FlaxEditor.Windows.Assets
base.OnDestroy(); base.OnDestroy();
} }
/// <inheritdoc />
protected virtual void OnScriptsReloadBegin()
{
if (!IsHidden)
{
Editor.Instance.Windows.AddToRestore(this);
}
}
#region IEditable Implementation #region IEditable Implementation
private bool _isEdited; private bool _isEdited;

View File

@@ -268,8 +268,11 @@ namespace FlaxEditor.Windows.Assets
UpdateKnowledge(); UpdateKnowledge();
} }
private void OnScriptsReloadBegin() /// <inheritdoc />
protected override void OnScriptsReloadBegin()
{ {
base.OnScriptsReloadBegin();
// TODO: impl hot-reload for BT to nicely refresh state (save asset, clear undo/properties, reload surface) // TODO: impl hot-reload for BT to nicely refresh state (save asset, clear undo/properties, reload surface)
Close(); Close();
} }

View File

@@ -200,7 +200,7 @@ namespace FlaxEditor.Windows.Assets
ViewportCamera = new FPSCamera(), ViewportCamera = new FPSCamera(),
Parent = _split.Panel1 Parent = _split.Panel1
}; };
_preview.Task.ViewFlags &= ~ViewFlags.Sky & ~ViewFlags.Bloom; _preview.Task.ViewFlags &= ~ViewFlags.Sky & ~ViewFlags.Bloom & ~ViewFlags.EyeAdaptation;
// Asset properties // Asset properties
_propertiesPresenter = new CustomEditorPresenter(null); _propertiesPresenter = new CustomEditorPresenter(null);

View File

@@ -124,8 +124,10 @@ namespace FlaxEditor.Windows.Assets
UpdateToolstrip(); UpdateToolstrip();
} }
private void OnScriptsReloadBegin() /// <inheritdoc />
protected override void OnScriptsReloadBegin()
{ {
base.OnScriptsReloadBegin();
Close(); Close();
} }

View File

@@ -2,7 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Drag; using FlaxEditor.GUI.Drag;
@@ -86,7 +85,7 @@ namespace FlaxEditor.Windows.Assets
{ {
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType); return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
} }
private static bool ValidateDragControlType(ScriptType controlType) private static bool ValidateDragControlType(ScriptType controlType)
{ {
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType); return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
@@ -171,7 +170,8 @@ namespace FlaxEditor.Windows.Assets
var actor = item.OnEditorDrop(this); var actor = item.OnEditorDrop(this);
actor.Name = item.ShortName; actor.Name = item.ShortName;
_window.Spawn(actor); _window.Spawn(actor);
var graphNode = _window.Graph.Root.Find(actor);; var graphNode = _window.Graph.Root.Find(actor);
;
if (graphNode != null) if (graphNode != null)
graphNodes.Add(graphNode); graphNodes.Add(graphNode);
} }
@@ -235,7 +235,8 @@ namespace FlaxEditor.Windows.Assets
} }
actor.Name = actorType.Name; actor.Name = actorType.Name;
_window.Spawn(actor); _window.Spawn(actor);
var graphNode = _window.Graph.Root.Find(actor);; var graphNode = _window.Graph.Root.Find(actor);
;
if (graphNode != null) if (graphNode != null)
graphNodes.Add(graphNode); graphNodes.Add(graphNode);
} }
@@ -290,7 +291,7 @@ namespace FlaxEditor.Windows.Assets
// Basic editing options // Basic editing options
var b = contextMenu.AddButton("Rename", Rename); var b = contextMenu.AddButton("Rename", RenameSelection);
b.Enabled = isSingleActorSelected; b.Enabled = isSingleActorSelected;
b = contextMenu.AddButton("Duplicate", Duplicate); b = contextMenu.AddButton("Duplicate", Duplicate);
@@ -414,7 +415,8 @@ namespace FlaxEditor.Windows.Assets
contextMenu.Show(parent, location); contextMenu.Show(parent, location);
} }
private void Rename() /// <inheritdoc />
public void RenameSelection()
{ {
var selection = Selection; var selection = Selection;
if (selection.Count != 0 && selection[0] is ActorNode actor) if (selection.Count != 0 && selection[0] is ActorNode actor)
@@ -425,6 +427,12 @@ namespace FlaxEditor.Windows.Assets
} }
} }
/// <inheritdoc />
public void FocusSelection()
{
_viewport.FocusSelection();
}
/// <summary> /// <summary>
/// Spawns the specified actor to the prefab (adds actor to root). /// Spawns the specified actor to the prefab (adds actor to root).
/// </summary> /// </summary>
@@ -468,7 +476,7 @@ namespace FlaxEditor.Windows.Assets
// Spawn it // Spawn it
Spawn(actor); Spawn(actor);
Rename(); RenameSelection();
} }
/// <summary> /// <summary>

View File

@@ -19,7 +19,7 @@ namespace FlaxEditor.Windows.Assets
/// </summary> /// </summary>
/// <seealso cref="Prefab" /> /// <seealso cref="Prefab" />
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" /> /// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
public sealed partial class PrefabWindow : AssetEditorWindowBase<Prefab>, IPresenterOwner public sealed partial class PrefabWindow : AssetEditorWindowBase<Prefab>, IPresenterOwner, ISceneContextWindow
{ {
private readonly SplitPanel _split1; private readonly SplitPanel _split1;
private readonly SplitPanel _split2; private readonly SplitPanel _split2;
@@ -194,7 +194,6 @@ namespace FlaxEditor.Windows.Assets
Editor.Prefabs.PrefabApplied += OnPrefabApplied; Editor.Prefabs.PrefabApplied += OnPrefabApplied;
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin; ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
// Setup input actions // Setup input actions
InputActions.Add(options => options.Undo, () => InputActions.Add(options => options.Undo, () =>
@@ -212,8 +211,8 @@ namespace FlaxEditor.Windows.Assets
InputActions.Add(options => options.Paste, Paste); InputActions.Add(options => options.Paste, Paste);
InputActions.Add(options => options.Duplicate, Duplicate); InputActions.Add(options => options.Duplicate, Duplicate);
InputActions.Add(options => options.Delete, Delete); InputActions.Add(options => options.Delete, Delete);
InputActions.Add(options => options.Rename, Rename); InputActions.Add(options => options.Rename, RenameSelection);
InputActions.Add(options => options.FocusSelection, _viewport.FocusSelection); InputActions.Add(options => options.FocusSelection, FocusSelection);
} }
/// <summary> /// <summary>
@@ -287,8 +286,10 @@ namespace FlaxEditor.Windows.Assets
return false; return false;
} }
private void OnScriptsReloadBegin() /// <inheritdoc />
protected override void OnScriptsReloadBegin()
{ {
base.OnScriptsReloadBegin();
_isScriptsReloading = true; _isScriptsReloading = true;
if (_asset == null || !_asset.IsLoaded) if (_asset == null || !_asset.IsLoaded)
@@ -316,19 +317,8 @@ namespace FlaxEditor.Windows.Assets
Graph.MainActor = null; Graph.MainActor = null;
_viewport.Prefab = null; _viewport.Prefab = null;
_undo?.Clear(); // TODO: maybe don't clear undo? _undo?.Clear(); // TODO: maybe don't clear undo?
}
private void OnScriptsReloadEnd() Close();
{
_isScriptsReloading = false;
if (_asset == null || !_asset.IsLoaded)
return;
// Restore
OnPrefabOpened();
_undo.Clear();
ClearEditedFlag();
} }
private void OnUndoEvent(IUndoAction action) private void OnUndoEvent(IUndoAction action)
@@ -355,13 +345,22 @@ namespace FlaxEditor.Windows.Assets
private void OnPrefabOpened() private void OnPrefabOpened()
{ {
_viewport.Prefab = _asset; _viewport.Prefab = _asset;
_viewport.UpdateGizmoMode(); if (Editor.ProjectCache.TryGetCustomData($"UIMode:{_asset.ID}", out bool value))
_viewport.SetInitialUIMode(value);
else
_viewport.SetInitialUIMode(_viewport._hasUILinked);
_viewport.UIModeToggled += OnUIModeToggled;
Graph.MainActor = _viewport.Instance; Graph.MainActor = _viewport.Instance;
Selection.Clear(); Selection.Clear();
Select(Graph.Main); Select(Graph.Main);
Graph.Root.TreeNode.Expand(true); Graph.Root.TreeNode.Expand(true);
} }
private void OnUIModeToggled(bool value)
{
Editor.ProjectCache.SetCustomData($"UIMode:{_asset.ID}", value);
}
/// <inheritdoc /> /// <inheritdoc />
public override void Save() public override void Save()
{ {
@@ -538,7 +537,6 @@ namespace FlaxEditor.Windows.Assets
{ {
Editor.Prefabs.PrefabApplied -= OnPrefabApplied; Editor.Prefabs.PrefabApplied -= OnPrefabApplied;
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin; ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
_undo.Dispose(); _undo.Dispose();
Graph.Dispose(); Graph.Dispose();

View File

@@ -29,6 +29,7 @@ namespace FlaxEditor.Windows
private const string ProjectDataLastViewedFolder = "LastViewedFolder"; private const string ProjectDataLastViewedFolder = "LastViewedFolder";
private bool _isWorkspaceDirty; private bool _isWorkspaceDirty;
private string _workspaceRebuildLocation; private string _workspaceRebuildLocation;
private string _lastViewedFolderBeforeReload;
private SplitPanel _split; private SplitPanel _split;
private Panel _contentViewPanel; private Panel _contentViewPanel;
private Panel _contentTreePanel; private Panel _contentTreePanel;
@@ -144,26 +145,6 @@ namespace FlaxEditor.Windows
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
// Content database events
editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved;
editor.ContentDatabase.WorkspaceRebuilding += () => { _workspaceRebuildLocation = SelectedNode?.Path; };
editor.ContentDatabase.WorkspaceRebuilt += () =>
{
var selected = Editor.ContentDatabase.Find(_workspaceRebuildLocation);
if (selected is ContentFolder selectedFolder)
{
_navigationUnlocked = false;
RefreshView(selectedFolder.Node);
_tree.Select(selectedFolder.Node);
UpdateItemsSearch();
_navigationUnlocked = true;
UpdateUI();
}
else
ShowRoot();
};
var options = Editor.Options; var options = Editor.Options;
options.OptionsChanged += OnOptionsChanged; options.OptionsChanged += OnOptionsChanged;
@@ -1036,6 +1017,61 @@ namespace FlaxEditor.Windows
/// <inheritdoc /> /// <inheritdoc />
public override void OnInit() public override void OnInit()
{
// Content database events
Editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
Editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved;
Editor.ContentDatabase.WorkspaceRebuilding += () => { _workspaceRebuildLocation = SelectedNode?.Path; };
Editor.ContentDatabase.WorkspaceRebuilt += () =>
{
var selected = Editor.ContentDatabase.Find(_workspaceRebuildLocation);
if (selected is ContentFolder selectedFolder)
{
_navigationUnlocked = false;
RefreshView(selectedFolder.Node);
_tree.Select(selectedFolder.Node);
UpdateItemsSearch();
_navigationUnlocked = true;
UpdateUI();
}
else if (_root != null)
ShowRoot();
};
Refresh();
// Load last viewed folder
if (Editor.ProjectCache.TryGetCustomData(ProjectDataLastViewedFolder, out string lastViewedFolder))
{
if (Editor.ContentDatabase.Find(lastViewedFolder) is ContentFolder folder)
_tree.Select(folder.Node);
}
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
ScriptsBuilder.ScriptsReloadEnd += OnScriptsReloadEnd;
}
private void OnScriptsReloadBegin()
{
var lastViewedFolder = _tree.Selection.Count == 1 ? _tree.SelectedNode as ContentTreeNode : null;
_lastViewedFolderBeforeReload = lastViewedFolder?.Path ?? string.Empty;
_tree.RemoveChild(_root);
_root = null;
}
private void OnScriptsReloadEnd()
{
Refresh();
if (!string.IsNullOrEmpty(_lastViewedFolderBeforeReload))
{
if (Editor.ContentDatabase.Find(_lastViewedFolderBeforeReload) is ContentFolder folder)
_tree.Select(folder.Node);
}
}
private void Refresh()
{ {
// Setup content root node // Setup content root node
_root = new RootContentTreeNode _root = new RootContentTreeNode
@@ -1072,13 +1108,6 @@ namespace FlaxEditor.Windows
// Update UI layout // Update UI layout
_isLayoutLocked = false; _isLayoutLocked = false;
PerformLayout(); PerformLayout();
// Load last viewed folder
if (Editor.ProjectCache.TryGetCustomData(ProjectDataLastViewedFolder, out string lastViewedFolder))
{
if (Editor.ContentDatabase.Find(lastViewedFolder) is ContentFolder folder)
_tree.Select(folder.Node);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -1226,6 +1255,8 @@ namespace FlaxEditor.Windows
_viewDropdown = null; _viewDropdown = null;
Editor.Options.OptionsChanged -= OnOptionsChanged; Editor.Options.OptionsChanged -= OnOptionsChanged;
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
base.OnDestroy(); base.OnDestroy();
} }

View File

@@ -95,15 +95,15 @@ namespace FlaxEditor.Windows
{ {
case LogType.Warning: case LogType.Warning:
Group = LogGroup.Warning; Group = LogGroup.Warning;
Icon = _window.IconWarning; Icon = _window._iconWarning;
break; break;
case LogType.Info: case LogType.Info:
Group = LogGroup.Info; Group = LogGroup.Info;
Icon = _window.IconInfo; Icon = _window._iconInfo;
break; break;
default: default:
Group = LogGroup.Error; Group = LogGroup.Error;
Icon = _window.IconError; Icon = _window._iconError;
break; break;
} }
} }
@@ -131,20 +131,21 @@ namespace FlaxEditor.Windows
else if (index % 2 == 0) else if (index % 2 == 0)
Render2D.FillRectangle(clientRect, style.Background * 0.9f); Render2D.FillRectangle(clientRect, style.Background * 0.9f);
var color = Group == LogGroup.Error ? _window._colorError : (Group == LogGroup.Warning ? _window._colorWarning : _window._colorInfo);
// Icon // Icon
var iconColor = Group == LogGroup.Error ? Color.Red : (Group == LogGroup.Warning ? Color.Yellow : style.Foreground); Render2D.DrawSprite(Icon, new Rectangle(5, 0, 32, 32), color);
Render2D.DrawSprite(Icon, new Rectangle(5, 0, 32, 32), iconColor);
// Title // Title
var textRect = new Rectangle(38, 2, clientRect.Width - 40, clientRect.Height - 10); var textRect = new Rectangle(38, 2, clientRect.Width - 40, clientRect.Height - 10);
Render2D.PushClip(ref clientRect); Render2D.PushClip(ref clientRect);
if (LogCount == 1) if (LogCount == 1)
{ {
Render2D.DrawText(style.FontMedium, Desc.Title, textRect, style.Foreground); Render2D.DrawText(style.FontMedium, Desc.Title, textRect, color);
} }
else if (LogCount > 1) else if (LogCount > 1)
{ {
Render2D.DrawText(style.FontMedium, $"{Desc.Title} ({LogCount})", textRect, style.Foreground); Render2D.DrawText(style.FontMedium, $"{Desc.Title} ({LogCount})", textRect, color);
} }
Render2D.PopClip(); Render2D.PopClip();
} }
@@ -304,10 +305,12 @@ namespace FlaxEditor.Windows
private readonly ToolStripButton[] _groupButtons = new ToolStripButton[3]; private readonly ToolStripButton[] _groupButtons = new ToolStripButton[3];
private LogType _iconType = LogType.Info; private LogType _iconType = LogType.Info;
private SpriteHandle _iconInfo;
internal SpriteHandle IconInfo; private SpriteHandle _iconWarning;
internal SpriteHandle IconWarning; private SpriteHandle _iconError;
internal SpriteHandle IconError; private Color _colorInfo;
private Color _colorWarning;
private Color _colorError;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DebugLogWindow"/> class. /// Initializes a new instance of the <see cref="DebugLogWindow"/> class.
@@ -317,7 +320,7 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None) : base(editor, true, ScrollBars.None)
{ {
Title = "Debug Log"; Title = "Debug Log";
Icon = IconInfo; Icon = _iconInfo;
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this); FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
// Toolstrip // Toolstrip
@@ -361,7 +364,6 @@ namespace FlaxEditor.Windows
editor.Options.Apply(editor.Options.Options); editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Shows/hides info messages"); }).SetAutoCheck(true).LinkTooltip("Shows/hides info messages");
UpdateCount(); UpdateCount();
OnEditorOptionsChanged(Editor.Options.Options);
// Split panel // Split panel
_split = new SplitPanel(Orientation.Vertical, ScrollBars.Vertical, ScrollBars.Both) _split = new SplitPanel(Orientation.Vertical, ScrollBars.Vertical, ScrollBars.Both)
@@ -394,14 +396,17 @@ namespace FlaxEditor.Windows
}; };
// Cache entries icons // Cache entries icons
IconInfo = Editor.Icons.Info64; _iconInfo = Editor.Icons.Info64;
IconWarning = Editor.Icons.Warning64; _iconWarning = Editor.Icons.Warning64;
IconError = Editor.Icons.Error64; _iconError = Editor.Icons.Error64;
// Bind events // Bind events
Editor.Options.OptionsChanged += OnEditorOptionsChanged; Editor.Options.OptionsChanged += OnEditorOptionsChanged;
Debug.Logger.LogHandler.SendLog += LogHandlerOnSendLog; Debug.Logger.LogHandler.SendLog += LogHandlerOnSendLog;
Debug.Logger.LogHandler.SendExceptionLog += LogHandlerOnSendExceptionLog; Debug.Logger.LogHandler.SendExceptionLog += LogHandlerOnSendExceptionLog;
// Init editor options
OnEditorOptionsChanged(Editor.Options.Options);
} }
private void OnEditorOptionsChanged(EditorOptions options) private void OnEditorOptionsChanged(EditorOptions options)
@@ -413,6 +418,9 @@ namespace FlaxEditor.Windows
_groupButtons[0].Checked = options.Interface.DebugLogShowErrorMessages; _groupButtons[0].Checked = options.Interface.DebugLogShowErrorMessages;
_groupButtons[1].Checked = options.Interface.DebugLogShowWarningMessages; _groupButtons[1].Checked = options.Interface.DebugLogShowWarningMessages;
_groupButtons[2].Checked = options.Interface.DebugLogShowInfoMessages; _groupButtons[2].Checked = options.Interface.DebugLogShowInfoMessages;
_colorInfo = options.Interface.OutputLogTextColor;
_colorWarning = options.Interface.OutputLogWarningTextColor;
_colorError = options.Interface.OutputLogErrorTextColor;
} }
/// <summary> /// <summary>
@@ -422,7 +430,6 @@ namespace FlaxEditor.Windows
{ {
if (_entriesPanel == null) if (_entriesPanel == null)
return; return;
RemoveEntries(); RemoveEntries();
} }

View File

@@ -23,6 +23,8 @@ namespace FlaxEditor.Windows
private readonly GameRoot _guiRoot; private readonly GameRoot _guiRoot;
private bool _showGUI = true; private bool _showGUI = true;
private bool _showDebugDraw = false; private bool _showDebugDraw = false;
private bool _audioMuted = false;
private float _audioVolume = 1;
private bool _isMaximized = false, _isUnlockingMouse = false; private bool _isMaximized = false, _isUnlockingMouse = false;
private bool _isFloating = false, _isBorderless = false; private bool _isFloating = false, _isBorderless = false;
private bool _cursorVisible = true; private bool _cursorVisible = true;
@@ -91,6 +93,35 @@ namespace FlaxEditor.Windows
set => _showDebugDraw = value; set => _showDebugDraw = value;
} }
/// <summary>
/// Gets or set a value indicating whether Audio is muted.
/// </summary>
public bool AudioMuted
{
get => _audioMuted;
set
{
Audio.MasterVolume = value ? 0 : AudioVolume;
_audioMuted = value;
}
}
/// <summary>
/// Gets or sets a value that set the audio volume.
/// </summary>
public float AudioVolume
{
get => _audioVolume;
set
{
if (!AudioMuted)
Audio.MasterVolume = value;
_audioVolume = value;
}
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the game window is maximized (only in play mode). /// Gets or sets a value indicating whether the game window is maximized (only in play mode).
/// </summary> /// </summary>
@@ -646,6 +677,24 @@ namespace FlaxEditor.Windows
checkbox.StateChanged += x => ShowDebugDraw = x.Checked; checkbox.StateChanged += x => ShowDebugDraw = x.Checked;
} }
menu.AddSeparator();
// Mute Audio
{
var button = menu.AddButton("Mute Audio");
button.CloseMenuOnClick = false;
var checkbox = new CheckBox(140, 2, AudioMuted) { Parent = button };
checkbox.StateChanged += x => AudioMuted = x.Checked;
}
// Audio Volume
{
var button = menu.AddButton("Audio Volume");
button.CloseMenuOnClick = false;
var slider = new FloatValueBox(AudioVolume, 140, 2, 50, 0, 1) { Parent = button };
slider.ValueChanged += () => AudioVolume = slider.Value;
}
menu.MinimumWidth = 200; menu.MinimumWidth = 200;
menu.AddSeparator(); menu.AddSeparator();
} }

View File

@@ -286,7 +286,9 @@ namespace FlaxEditor.Windows
_output.DefaultStyle.Font == options.Interface.OutputLogTextFont && _output.DefaultStyle.Font == options.Interface.OutputLogTextFont &&
_output.DefaultStyle.Color == options.Interface.OutputLogTextColor && _output.DefaultStyle.Color == options.Interface.OutputLogTextColor &&
_output.DefaultStyle.ShadowColor == options.Interface.OutputLogTextShadowColor && _output.DefaultStyle.ShadowColor == options.Interface.OutputLogTextShadowColor &&
_output.DefaultStyle.ShadowOffset == options.Interface.OutputLogTextShadowOffset) _output.DefaultStyle.ShadowOffset == options.Interface.OutputLogTextShadowOffset &&
_output.WarningStyle.Color == options.Interface.OutputLogWarningTextColor &&
_output.ErrorStyle.Color == options.Interface.OutputLogErrorTextColor)
return; return;
_output.DefaultStyle = new TextBlockStyle _output.DefaultStyle = new TextBlockStyle
@@ -297,10 +299,11 @@ namespace FlaxEditor.Windows
ShadowOffset = options.Interface.OutputLogTextShadowOffset, ShadowOffset = options.Interface.OutputLogTextShadowOffset,
BackgroundSelectedBrush = new SolidColorBrush(Style.Current.BackgroundSelected), BackgroundSelectedBrush = new SolidColorBrush(Style.Current.BackgroundSelected),
}; };
_output.WarningStyle = _output.DefaultStyle; _output.WarningStyle = _output.DefaultStyle;
_output.WarningStyle.Color = Color.Yellow; _output.WarningStyle.Color = options.Interface.OutputLogWarningTextColor;
_output.ErrorStyle = _output.DefaultStyle; _output.ErrorStyle = _output.DefaultStyle;
_output.ErrorStyle.Color = Color.Red; _output.ErrorStyle.Color = options.Interface.OutputLogErrorTextColor;
_timestampsFormats = options.Interface.OutputLogTimestampsFormat; _timestampsFormats = options.Interface.OutputLogTimestampsFormat;
_showLogType = options.Interface.OutputLogShowLogType; _showLogType = options.Interface.OutputLogShowLogType;
@@ -601,7 +604,7 @@ namespace FlaxEditor.Windows
var cachedScrollValue = _vScroll.Value; var cachedScrollValue = _vScroll.Value;
var cachedSelection = _output.SelectionRange; var cachedSelection = _output.SelectionRange;
var cachedOutputTargetViewOffset = _output.TargetViewOffset; var cachedOutputTargetViewOffset = _output.TargetViewOffset;
var isBottomScroll = _vScroll.Value >= _vScroll.Maximum - (_scrollSize*2) || wasEmpty; var isBottomScroll = _vScroll.Value >= _vScroll.Maximum - (_scrollSize * 2) || wasEmpty;
_output.Text = _textBuffer.ToString(); _output.Text = _textBuffer.ToString();
_output.TargetViewOffset = cachedOutputTargetViewOffset; _output.TargetViewOffset = cachedOutputTargetViewOffset;
_textBufferCount = _entries.Count; _textBufferCount = _entries.Count;

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