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

View File

@@ -1,4 +1,4 @@
# Redirect to our own Git LFS server
[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
echo Building C# bindings...
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
popd
echo Done!

View File

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

View File

@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
# TODO: Detect the correct architecture here
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ namespace FlaxEditor.Actions
public Guid PrefabID;
public Guid PrefabObjectID;
public unsafe Item(SceneObject obj, List<Item> nestedPrefabLinks)
public Item(SceneObject obj, List<Item> nestedPrefabLinks)
{
ID = obj.ID;
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)
Item nested;
nested.ID = ID;
fixed (Item* i = &this)
Editor.Internal_GetPrefabNestedObject(new IntPtr(&i->PrefabID), new IntPtr(&i->PrefabObjectID), new IntPtr(&nested.PrefabID), new IntPtr(&nested.PrefabObjectID));
Editor.GetPrefabNestedObject(ref PrefabID, ref PrefabObjectID, out nested.PrefabID, out nested.PrefabObjectID);
if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty)
nestedPrefabLinks.Add(nested);
}

View File

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

View File

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

View File

@@ -236,19 +236,19 @@ namespace FlaxEditor.Utilities
/// <summary>
/// The time/value axes tick steps for editors with timeline.
/// </summary>
internal static readonly float[] CurveTickSteps =
internal static readonly double[] CurveTickSteps =
{
0.0000001f, 0.0000005f, 0.000001f, 0.000005f, 0.00001f,
0.00005f, 0.0001f, 0.0005f, 0.001f, 0.005f,
0.01f, 0.05f, 0.1f, 0.5f, 1,
0.0000001, 0.0000005, 0.000001, 0.000005, 0.00001,
0.00005, 0.0001, 0.0005, 0.001, 0.005,
0.01, 0.05, 0.1, 0.5, 1,
5, 10, 50, 100, 500,
1000, 5000, 10000, 50000, 100000,
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)
return Int2.Zero;
@@ -262,10 +262,10 @@ namespace FlaxEditor.Utilities
for (int i = tickSteps.Length - 1; i >= 0; i--)
{
// 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
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
if (tickStrengths[i] >= 1)
@@ -283,7 +283,7 @@ namespace FlaxEditor.Utilities
// Draw all tick levels
for (int level = 0; level < tickLevels; level++)
{
float strength = tickStrengths[smallestTick + level];
var strength = tickStrengths[smallestTick + level];
if (strength <= Mathf.Epsilon)
continue;
@@ -291,20 +291,36 @@ namespace FlaxEditor.Utilities
int l = Mathf.Clamp(smallestTick + level, 0, tickSteps.Length - 2);
var lStep = tickSteps[l];
var lNextStep = tickSteps[l + 1];
int startTick = Mathf.FloorToInt(min / lStep);
int endTick = Mathf.CeilToInt(max / lStep);
for (int i = startTick; i <= endTick; i++)
var startTick = Mathd.FloorToInt(min / lStep);
var endTick = Mathd.CeilToInt(max / lStep);
for (var i = startTick; i <= endTick; i++)
{
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
continue;
var tick = i * lStep;
drawTick(tick, strength);
var tick = (decimal)lStep * i;
drawTick(tick, lStep, strength);
}
}
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>
/// Determines whether the specified path string contains any invalid character.
/// </summary>
@@ -1528,5 +1544,12 @@ namespace FlaxEditor.Utilities
}
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 FlaxEditor.Content;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Cameras;
using FlaxEditor.Viewport.Previews;
using FlaxEditor.Viewport.Widgets;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -44,7 +46,7 @@ namespace FlaxEditor.Viewport
private sealed class PrefabUIEditorRoot : UIEditorRoot
{
private readonly PrefabWindowViewport _viewport;
private bool UI => _viewport._hasUILinkedCached;
private bool UI => _viewport.ShowUI;
public PrefabUIEditorRoot(PrefabWindowViewport viewport)
: base(true)
@@ -67,8 +69,78 @@ namespace FlaxEditor.Viewport
private PrefabSpritesRenderer _spritesRenderer;
private IntPtr _tempDebugDrawContext;
private bool _hasUILinkedCached;
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>
/// Drag and drop handlers
@@ -138,6 +210,11 @@ namespace FlaxEditor.Viewport
_uiRoot.IndexInParent = 0; // Move viewport down below other widgets in the viewport
_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);
// Setup input actions
@@ -146,58 +223,8 @@ namespace FlaxEditor.Viewport
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)
{
UpdateGizmoMode();
for (int i = 0; i < Gizmos.Count; i++)
{
Gizmos[i].Update(deltaTime);

View File

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

View File

@@ -268,8 +268,11 @@ namespace FlaxEditor.Windows.Assets
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)
Close();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ namespace FlaxEditor.Windows
private const string ProjectDataLastViewedFolder = "LastViewedFolder";
private bool _isWorkspaceDirty;
private string _workspaceRebuildLocation;
private string _lastViewedFolderBeforeReload;
private SplitPanel _split;
private Panel _contentViewPanel;
private Panel _contentTreePanel;
@@ -144,26 +145,6 @@ namespace FlaxEditor.Windows
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;
options.OptionsChanged += OnOptionsChanged;
@@ -1036,6 +1017,61 @@ namespace FlaxEditor.Windows
/// <inheritdoc />
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
_root = new RootContentTreeNode
@@ -1072,13 +1108,6 @@ namespace FlaxEditor.Windows
// Update UI layout
_isLayoutLocked = false;
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 />
@@ -1226,6 +1255,8 @@ namespace FlaxEditor.Windows
_viewDropdown = null;
Editor.Options.OptionsChanged -= OnOptionsChanged;
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
ScriptsBuilder.ScriptsReloadEnd -= OnScriptsReloadEnd;
base.OnDestroy();
}

View File

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

View File

@@ -23,6 +23,8 @@ namespace FlaxEditor.Windows
private readonly GameRoot _guiRoot;
private bool _showGUI = true;
private bool _showDebugDraw = false;
private bool _audioMuted = false;
private float _audioVolume = 1;
private bool _isMaximized = false, _isUnlockingMouse = false;
private bool _isFloating = false, _isBorderless = false;
private bool _cursorVisible = true;
@@ -91,6 +93,35 @@ namespace FlaxEditor.Windows
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>
/// Gets or sets a value indicating whether the game window is maximized (only in play mode).
/// </summary>
@@ -646,6 +677,24 @@ namespace FlaxEditor.Windows
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.AddSeparator();
}

View File

@@ -286,7 +286,9 @@ namespace FlaxEditor.Windows
_output.DefaultStyle.Font == options.Interface.OutputLogTextFont &&
_output.DefaultStyle.Color == options.Interface.OutputLogTextColor &&
_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;
_output.DefaultStyle = new TextBlockStyle
@@ -297,10 +299,11 @@ namespace FlaxEditor.Windows
ShadowOffset = options.Interface.OutputLogTextShadowOffset,
BackgroundSelectedBrush = new SolidColorBrush(Style.Current.BackgroundSelected),
};
_output.WarningStyle = _output.DefaultStyle;
_output.WarningStyle.Color = Color.Yellow;
_output.WarningStyle.Color = options.Interface.OutputLogWarningTextColor;
_output.ErrorStyle = _output.DefaultStyle;
_output.ErrorStyle.Color = Color.Red;
_output.ErrorStyle.Color = options.Interface.OutputLogErrorTextColor;
_timestampsFormats = options.Interface.OutputLogTimestampsFormat;
_showLogType = options.Interface.OutputLogShowLogType;
@@ -601,7 +604,7 @@ namespace FlaxEditor.Windows
var cachedScrollValue = _vScroll.Value;
var cachedSelection = _output.SelectionRange;
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.TargetViewOffset = cachedOutputTargetViewOffset;
_textBufferCount = _entries.Count;

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