327 Commits

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
Wojtek Figat
1475075b00 Merge branch 'GoaLitiuM-dotnet_refasm_version_fix' 2025-01-27 20:29:16 +01:00
Wojtek Figat
702564366d Merge branch 'dotnet_refasm_version_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-dotnet_refasm_version_fix 2025-01-27 20:29:12 +01:00
Wojtek Figat
e2fd3891d1 Fix regression in curve keyframes editing
#3179
2025-01-27 20:19:35 +01:00
f54e961f11 Update .NET compilation instructions for Arch 2025-01-27 20:35:56 +02:00
Wojtek Figat
aabd70fbe7 Fix code project files generation to properly handle path slashes and ignore binary modules without exports
#3086
2025-01-27 19:35:27 +01:00
428ebf7fd7 Fix .NET runtime and SDK compilation issues with newer runtime 2025-01-27 20:06:06 +02:00
Wojtek Figat
72f16d738f Merge branch 'Tryibion-draw-anchors' 2025-01-27 12:41:01 +01:00
Wojtek Figat
475818554d Fix error in editor when sliding value 2025-01-27 12:40:55 +01:00
Wojtek Figat
8ebb3a3215 Merge branch 'draw-anchors' of https://github.com/Tryibion/FlaxEngine into Tryibion-draw-anchors 2025-01-27 12:12:24 +01:00
Wojtek Figat
2085a0bf25 Merge branch 'amir9480-fix_issue_3083' 2025-01-27 11:58:46 +01:00
Wojtek Figat
d829461def Merge branch 'fix_issue_3083' of https://github.com/amir9480/FlaxEngine into amir9480-fix_issue_3083 2025-01-27 11:58:13 +01:00
Wojtek Figat
2d169fdcd8 Merge branch 'Tryibion-particle-rotate-shape' 2025-01-27 11:43:04 +01:00
Wojtek Figat
53ba5968fd Fix missing default value usage on GPU particle shape rotation and simplify CPU code
#3104
2025-01-27 11:42:59 +01:00
Wojtek Figat
cc735a1b6a Merge branch 'particle-rotate-shape' of https://github.com/Tryibion/FlaxEngine into Tryibion-particle-rotate-shape 2025-01-27 11:35:26 +01:00
Wojtek Figat
970af7bdc8 Attempt to fix recent Github CD failing 2025-01-27 11:35:10 +01:00
Wojtek Figat
2ff6a6dd9a Merge branch 'Tryibion-clamp-anchors' 2025-01-26 22:05:40 +01:00
Wojtek Figat
ae3149c9c0 Merge branch 'clamp-anchors' of https://github.com/Tryibion/FlaxEngine into Tryibion-clamp-anchors 2025-01-26 22:05:36 +01:00
Wojtek Figat
1a1bd56802 Merge branch 'GoaLitiuM-sln_folder_fix' 2025-01-26 22:03:11 +01:00
Wojtek Figat
25b566b348 Merge branch 'sln_folder_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-sln_folder_fix 2025-01-26 22:02:58 +01:00
Wojtek Figat
4fb95a704a Merge branch 'Tryibion-file-path-drag-dop' 2025-01-26 21:59:04 +01:00
Wojtek Figat
5f09ef4c1f Merge branch 'file-path-drag-dop' of https://github.com/Tryibion/FlaxEngine into Tryibion-file-path-drag-dop 2025-01-26 21:58:34 +01:00
Wojtek Figat
7bc099c32c Merge branch 'Tryibion-content-item-text-scale' 2025-01-25 11:09:36 +01:00
Wojtek Figat
9a59d0c5ed Merge branch 'content-item-text-scale' of https://github.com/Tryibion/FlaxEngine into Tryibion-content-item-text-scale 2025-01-25 10:05:54 +01:00
Wojtek Figat
275ca296fa Fix editor orthographic viewport in top or bottom view
#3169
2025-01-25 00:38:51 +01:00
Wojtek Figat
57af076c8d Merge branch 'Tryibion-is-active-null-check' 2025-01-24 23:51:48 +01:00
Chandler Cox
f905c49f0b Change content item text scale with content view scale. 2025-01-24 13:02:05 -06:00
Chandler Cox
c72fac335f Check for null in Actor node IsActive. 2025-01-23 21:28:09 -06:00
Chandler Cox
030befdcaa Rename dropped method. 2025-01-22 21:47:28 -06:00
Chandler Cox
3a591577ad Add drag drop to FilePathEditor 2025-01-22 21:46:21 -06:00
Chandler Cox
8f9eaddbe5 Add anchor and pivot drawing for UI Gizmo. 2025-01-20 21:08:47 -06:00
Amir Alizadeh
ec11a79f55 Add raycast support to the ContainerControl 2025-01-19 23:55:56 +03:30
Amir Alizadeh
55fd198102 Add raycast-first priority to the UIEditorGizmo 2025-01-19 23:55:23 +03:30
Chandler Cox
425699c4b0 Clamp control anchors betwen 0 and 1. 2025-01-19 13:51:50 -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
af3badaeef Fix Visual Studio solution nested project names on Unix systems 2025-01-14 19:08:09 +02:00
Wojtek Figat
f17d6f62ab Merge branch 'Tryibion-use-version' 2025-01-13 17:32:03 +01:00
Wojtek Figat
ae3d437539 Merge branch 'use-version' of https://github.com/Tryibion/FlaxEngine into Tryibion-use-version 2025-01-13 17:31:53 +01:00
Wojtek Figat
99b737eb14 Merge branch 'Tryibion-aab-building' 2025-01-13 17:31:38 +01:00
Wojtek Figat
4add5dcf49 Add missing default value and fix doc comment
#3150
2025-01-13 17:31:34 +01:00
Wojtek Figat
a204ada6d3 Merge branch 'aab-building' of https://github.com/Tryibion/FlaxEngine into Tryibion-aab-building 2025-01-13 17:18:35 +01:00
Wojtek Figat
bdc7f0760f Merge branch 'Tryibion-re-enable-scale-center' 2025-01-13 17:17:12 +01:00
Wojtek Figat
07ef2f03d5 Merge branch 're-enable-scale-center' of https://github.com/Tryibion/FlaxEngine into Tryibion-re-enable-scale-center 2025-01-13 17:12:20 +01:00
Wojtek Figat
b5437a9097 Merge branch 'Tryibion-fix-actor-drop-focus' 2025-01-13 17:11:48 +01:00
Wojtek Figat
890c3e75c3 Merge branch 'fix-actor-drop-focus' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-actor-drop-focus 2025-01-13 16:08:56 +01:00
Wojtek Figat
7fcf8c2d4c Improve #3138 to pass over setting value to null and via proper cast so value type stays the same 2025-01-13 16:08:43 +01:00
Wojtek Figat
3796b0ccae Revert #3117 and do it different way as some types can be valid even if different thus use internal parameter setter for type validation 2025-01-13 16:07:47 +01:00
Wojtek Figat
bc18ddc04b Merge branch 'Tryibion-invert-channels' 2025-01-13 15:46:49 +01:00
Wojtek Figat
90316dfa52 Minor code changes to PR 2025-01-13 15:46:35 +01:00
Chandler Cox
55fa372197 re-add returns to aab 2025-01-13 07:30:01 -06:00
Chandler Cox
563f0b9ab4 Move Build .aab to Android platform settings and make it side-by-side 2025-01-13 07:24:50 -06:00
Chandler Cox
30ea3bc9c2 Add check for empty array and use IsInRange for version check. 2025-01-13 07:16:31 -06:00
Wojtek Figat
07b9e5bfdd Merge branch 'invert-channels' of https://github.com/Tryibion/FlaxEngine into Tryibion-invert-channels 2025-01-13 09:20:22 +01:00
Chandler Cox
f274639e94 Fix path bug. 2025-01-12 17:17:59 -06:00
Wojtek Figat
7ac2376231 Simplify code 2025-01-12 23:57:52 +01:00
Chandler Cox
01d1dbba6c Add aditional check for if custom define of BuildAAB already exists. 2025-01-12 16:57:19 -06:00
Chandler Cox
ca995093b6 Add .aab bundling for Android. 2025-01-12 16:50:16 -06:00
Wojtek Figat
f36d3a11ab Merge branch 'Tryibion-handle-multi-linked' 2025-01-12 22:13:11 +01:00
Wojtek Figat
06a04167c7 Merge branch 'handle-multi-linked' of https://github.com/Tryibion/FlaxEngine into Tryibion-handle-multi-linked 2025-01-12 22:13:07 +01:00
Chandler Cox
e2df7a1e85 Handle linked values in Float3Editor 2025-01-12 15:07:43 -06:00
Wojtek Figat
80f5b554cd Merge branch 'Tryibion-fix-run-cooked-game' 2025-01-12 22:01:34 +01:00
Wojtek Figat
f10404a948 Merge branch 'fix-run-cooked-game' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-run-cooked-game 2025-01-12 22:01:29 +01:00
Wojtek Figat
a9580b9b46 Merge branch 'Tryibion-anim-param-warn-type' 2025-01-12 22:00:35 +01:00
Wojtek Figat
3d76a99c9b Merge branch 'anim-param-warn-type' of https://github.com/Tryibion/FlaxEngine into Tryibion-anim-param-warn-type 2025-01-12 22:00:30 +01:00
Wojtek Figat
eaeeea6a81 Merge branch 'Tryibion-import-ui-spacing' 2025-01-12 21:59:43 +01:00
Wojtek Figat
b546e4a332 Merge branch 'import-ui-spacing' of https://github.com/Tryibion/FlaxEngine into Tryibion-import-ui-spacing 2025-01-12 21:59:28 +01:00
Wojtek Figat
281e13b42c Merge branch 'xxSeys1-EditPrefabNoContentPanelChange' 2025-01-12 21:58:23 +01:00
Wojtek Figat
8451439abb Merge branch 'EditPrefabNoContentPanelChange' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-EditPrefabNoContentPanelChange 2025-01-12 21:58:19 +01:00
Wojtek Figat
95c9df2581 Merge branch 'Tryibion-no-params-ui' 2025-01-12 21:57:17 +01:00
Wojtek Figat
2699755581 Merge branch 'no-params-ui' of https://github.com/Tryibion/FlaxEngine into Tryibion-no-params-ui 2025-01-12 21:57:12 +01:00
Wojtek Figat
99b0fbee07 Merge branch 'Tryibion-fix-multiblend-exception' 2025-01-12 21:56:32 +01:00
Wojtek Figat
f153c67c0e Merge branch 'fix-multiblend-exception' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-multiblend-exception 2025-01-12 21:56:28 +01:00
Wojtek Figat
fa8857be0e Merge branch 'Tryibion-fix-cpu-profiler-crash' 2025-01-12 21:55:44 +01:00
Chandler Cox
2260236fa6 Fix CPU profiler crash on conversion to ulong. 2025-01-09 20:55:30 -06:00
Chandler Cox
cb7fc6141d Fix crash in multiblend 2d node when first created. 2025-01-09 19:40:36 -06:00
Chandler Cox
77c48c037e Add No parameters UI to particle effect and animated model 2025-01-09 19:19:30 -06:00
Chandler Cox
ccbcab9793 Fix android build on .net9 and use DotNet version that is found by build tool path. 2025-01-08 22:11:21 -06:00
Chandler Cox
e87bb2325b Standardize spacing for import path ui in assets. add import path ui to model prefab. 2025-01-07 20:43:57 -06:00
Chandler Cox
13863344d2 Warn if value is the wrong type for the animation graph parameter trying to be set. 2025-01-07 20:26:25 -06:00
Wojtek Figat
3133ebbd83 Merge branch 'Tryibion-mat-warn-wrong-type' 2025-01-06 23:58:04 +01:00
Wojtek Figat
bff25a8dd8 Merge branch 'mat-warn-wrong-type' of https://github.com/Tryibion/FlaxEngine into Tryibion-mat-warn-wrong-type 2025-01-06 23:57:59 +01:00
Wojtek Figat
a9d0f62039 Merge branch 'Tryibion-import-path-ui' 2025-01-06 23:55:09 +01:00
Wojtek Figat
5335594cb5 Merge branch 'import-path-ui' of https://github.com/Tryibion/FlaxEngine into Tryibion-import-path-ui 2025-01-06 23:55:04 +01:00
Wojtek Figat
3f201c3863 Resave terrain material
#3115
2025-01-06 23:53:27 +01:00
Wojtek Figat
3dc3406230 Merge branch 'Tryibion-fix-size-handles-rotation' 2025-01-06 23:47:25 +01:00
Wojtek Figat
0b99cb6de5 Merge branch 'fix-size-handles-rotation' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-size-handles-rotation 2025-01-06 23:47:17 +01:00
Wojtek Figat
deab78d6b1 Merge branch 'Tryibion-text-box-ui' 2025-01-06 23:46:35 +01:00
Wojtek Figat
45c01e7ada Merge branch 'text-box-ui' of https://github.com/Tryibion/FlaxEngine into Tryibion-text-box-ui 2025-01-06 23:46:28 +01:00
Wojtek Figat
bcc8544c46 Merge branch 'Duroxxigar-add-confirmation-dialog-for-editor' 2025-01-06 23:46:21 +01:00
Wojtek Figat
597bbf1f30 Merge branch 'add-confirmation-dialog-for-editor' of https://github.com/Duroxxigar/FlaxEngine into Duroxxigar-add-confirmation-dialog-for-editor 2025-01-06 23:46:03 +01:00
Wojtek Figat
67b5b74588 Merge branch 'Duroxxigar-load-product-typo-fix' 2025-01-06 23:45:44 +01:00
Wojtek Figat
39f2f0ccdf Merge branch 'load-product-typo-fix' of https://github.com/Duroxxigar/FlaxEngine into Duroxxigar-load-product-typo-fix 2025-01-06 23:45:39 +01:00
Wojtek Figat
6ad2cd0697 Merge branch 'Tryibion-gameplugin-template' 2025-01-06 23:45:15 +01:00
Wojtek Figat
ef01a4afeb Merge branch 'gameplugin-template' of https://github.com/Tryibion/FlaxEngine into Tryibion-gameplugin-template 2025-01-06 23:45:10 +01:00
Wojtek Figat
12b98f2df1 Migrate to actions/upload-artifact@v4
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
2025-01-06 23:44:34 +01:00
Chandler Cox
99ba59d02a Change to use static method for import path ui. 2025-01-06 15:58:09 -06:00
Chandler Cox
7eb2088af0 Use Variant::CanCast() for type check. 2025-01-06 15:40:38 -06:00
Jake Young
a66cb4d1b2 Added a confirmation dialog for editors when the reset button is clicked. 2025-01-03 19:18:10 -05:00
Jake Young
22914dc232 Fix typo for error message when trying to load a project file that does not exist. 2025-01-03 17:31:21 -05:00
Chandler Cox
5af13bcc93 Re-enable scale center gizmo. 2025-01-03 13:04:52 -06:00
Chandler Cox
867f7d0143 Add local variables to simplify math. 2024-12-31 14:12:23 -06:00
Chandler Cox
26d0b9a42c Fix rotation of UI size handles. 2024-12-31 14:06:17 -06:00
Chandler Cox
f2e4fe300b Change color for readonly text. Fix selection still showing when text box is not focused. 2024-12-31 12:56:43 -06:00
Chandler Cox
a313db22d2 Add tooltip text for path to let user know it is not editable. 2024-12-31 12:52:54 -06:00
Chandler Cox
e53eddaba5 Add import path UI and button to open folder in asset import settings. 2024-12-31 12:38:29 -06:00
Chandler Cox
f71e731e54 Add saving and loading. 2024-12-30 23:42:32 -06:00
Chandler Cox
cb6ab6a647 Fix comment 2024-12-30 22:14:18 -06:00
Chandler Cox
899528e087 Add invert options for texture imports for Red, Blue, and Alpha channels. 2024-12-30 21:27:03 -06:00
Chandler Cox
6a8814c99a Fix .exe being deleted when using the "Run cooked build" option. 2024-12-29 17:08:10 -06:00
Chandler Cox
88703d721b Warn if wrong type while setting material parameter. 2024-12-23 16:51:37 -06:00
Chandler Cox
36d4417905 Add game plugin template. 2024-12-20 09:29:36 -06:00
Chandler Cox
873491eca2 Fix CPU particle code. 2024-12-12 21:07:00 -06:00
Chandler Cox
3ba1ebb847 Add rotate position shape as particle module. 2024-12-12 20:41:11 -06:00
Chandler Cox
f9e125f795 Select dropped actors that are reparented. 2024-12-03 17:59:30 -06: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
1fca41b31a code style fix 2024-10-09 18:29:48 +02:00
xxSeys1
8b3f1ca019 make "Edit Prefab" not change content panel file path
If someone still wants to change the Content panel to the file path of the prefab, they can use the "Select Prefab" button
2024-10-09 18:25:04 +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
533 changed files with 100121 additions and 4950 deletions

View File

@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libwayland-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -44,7 +44,7 @@ jobs:
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev libwayland-dev
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET

View File

@@ -1,12 +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=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
jobs:
@@ -20,7 +21,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git lfs pull
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -35,12 +36,12 @@ jobs:
run: |
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Windows-Editor
path: Output/Editor.zip
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Windows-EditorDebugSymbols
path: Output/EditorDebugSymbols.zip
@@ -53,7 +54,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git lfs pull
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -68,7 +69,7 @@ jobs:
run: |
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Windows-Game
path: Output/Windows.zip
@@ -83,7 +84,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git 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
@@ -101,7 +102,7 @@ jobs:
run: |
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Linux-Editor
path: Output/FlaxEditorLinux.zip
@@ -114,7 +115,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git 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
@@ -132,7 +133,7 @@ jobs:
run: |
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Linux-Game
path: Output/Linux.zip
@@ -147,7 +148,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git lfs pull
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -162,7 +163,7 @@ jobs:
run: |
./PackageEditor.command -arch=ARM64 -platform=Mac -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Mac-Editor
path: Output/FlaxEditorMac.zip
@@ -175,7 +176,7 @@ jobs:
- name: Checkout LFS
run: |
git lfs version
git lfs pull
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
- name: Setup Vulkan
uses: ./.github/actions/vulkan
- name: Setup .NET
@@ -190,7 +191,7 @@ jobs:
run: |
./PackagePlatforms.command -arch=ARM64 -platform=Mac -deployOutput=Output
- name: Upload
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Mac-Game
path: Output/Mac.zip

View File

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

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
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
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.

View File

@@ -0,0 +1,25 @@
%copyright%using System;
using System.Collections.Generic;
using FlaxEngine;
namespace %namespace%;
/// <summary>
/// %class% GamePlugin.
/// </summary>
public class %class% : GamePlugin
{
/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();
}
/// <inheritdoc/>
public override void Deinitialize()
{
base.Deinitialize();
}
}

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

@@ -13,6 +13,7 @@
"Configuration": {
"UseCSharp": true,
"UseLargeWorlds": false,
"UseDotNet": true
"UseDotNet": true,
"UseSDL": true
}
}

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

@@ -31,7 +31,7 @@ Follow the instructions below to compile and run the engine from source.
* Install Visual Studio 2022 or newer
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
* Install .NET 8 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Install .NET 8 or 9 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Install Git with LFS
* Clone repo (with LFS)
* Run **GenerateProjectFiles.bat**
@@ -44,8 +44,9 @@ Follow the instructions below to compile and run the engine from source.
## Linux
* Install Visual Studio Code
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Ubuntu: `sudo apt install dotnet-sdk-8.0`
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Ubuntu: `sudo apt install vulkan-sdk`
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
@@ -67,12 +68,12 @@ Follow the instructions below to compile and run the engine from source.
## Mac
* Install XCode
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Clone repo (with LFS)
* Run `GenerateProjectFiles.command`
* Open workspace with XCode or Visual Studio Code
* Build and run (configuration `Editor.Mac.Development`)
* Build and run (configuration `Editor.Mac.Development`)
#### Troubleshooting

View File

@@ -750,7 +750,8 @@ namespace FlaxEditor.Content
// Draw short name
Render2D.PushClip(ref textRect);
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, 0.95f);
var scale = 0.95f * view.ViewScale;
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, scale);
Render2D.PopClip();
if (IsBeingCut)

View File

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

View File

@@ -106,6 +106,23 @@ namespace FlaxEditor.Content
}
}
/// <summary>
/// Context proxy object for C# GamePlugin files.
/// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpProxy" />
[ContentContextMenu("New/C#/C# GamePlugin")]
public class CSharpGamePluginProxy : CSharpProxy
{
/// <inheritdoc />
public override string Name => "C# GamePlugin";
/// <inheritdoc />
protected override void GetTemplatePath(out string path)
{
path = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/GamePluginTemplate.cs");
}
}
/// <summary>
/// Context proxy object for empty C# files.
/// </summary>

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

@@ -671,11 +671,14 @@ bool GameCookerImpl::Build()
MCore::Thread::Attach();
// Build Started
CallEvent(GameCooker::EventType::BuildStarted);
data.Tools->OnBuildStarted(data);
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
Steps[stepIndex]->OnBuildStarted(data);
data.InitProgress(Steps.Count());
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
{
CallEvent(GameCooker::EventType::BuildStarted);
data.Tools->OnBuildStarted(data);
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
Steps[stepIndex]->OnBuildStarted(data);
data.InitProgress(Steps.Count());
}
// Execute all steps in a sequence
bool failed = false;
@@ -741,10 +744,13 @@ bool GameCookerImpl::Build()
}
IsRunning = false;
CancelFlag = 0;
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
Steps[stepIndex]->OnBuildEnded(data, failed);
data.Tools->OnBuildEnded(data, failed);
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
{
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
Steps[stepIndex]->OnBuildEnded(data, failed);
data.Tools->OnBuildEnded(data, failed);
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
}
Delete(Data);
Data = nullptr;

View File

@@ -364,6 +364,33 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
}
#endif
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
if (platformSettings->BuildAAB)
{
// .aab
{
CreateProcessSettings procSettings;
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT(":app:bundle") : TEXT(":app:bundleDebug"));
procSettings.WorkingDirectory = data.OriginalOutputPath;
const int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to build Gradle project into .aab package (result code: {0}). See log for more info."), result));
return true;
}
}
// Copy result package
const String aab = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/bundle/release/app-release.aab") : TEXT("app/build/outputs/bundle/debug/app-debug.aab"));
const String outputAab = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".aab");
if (FileSystem::CopyFile(outputAab, aab))
{
LOG(Error, "Failed to copy .aab package from {0} to {1}", aab, outputAab);
return true;
}
LOG(Info, "Output Android AAB application package: {0} (size: {1} MB)", outputAab, FileSystem::GetFileSize(outputAab) / 1024 / 1024);
}
// .apk
{
CreateProcessSettings procSettings;
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
@@ -371,20 +398,20 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
const int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
data.Error(String::Format(TEXT("Failed to build Gradle project into .apk package (result code: {0}). See log for more info."), result));
return true;
}
}
// Copy result package
const String apk = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/apk/release/app-release-unsigned.apk") : TEXT("app/build/outputs/apk/debug/app-debug.apk"));
const String outputApk = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".apk");
if (FileSystem::CopyFile(outputApk, apk))
{
LOG(Error, "Failed to copy package from {0} to {1}", apk, outputApk);
LOG(Error, "Failed to copy .apk package from {0} to {1}", apk, outputApk);
return true;
}
LOG(Info, "Output Android application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
LOG(Info, "Output Android APK application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
return false;
}

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

@@ -214,6 +214,33 @@ bool DeployDataStep::Perform(CookingData& data)
FileSystem::NormalizePath(srcDotnet);
LOG(Info, "Using .NET Runtime {} at {}", TEXT("Host"), srcDotnet);
// Get major Version
Array<String> pathParts;
srcDotnet.Split('/', pathParts);
String version;
for (int i = 0; i < pathParts.Count(); i++)
{
if (pathParts[i] == TEXT("runtimes"))
{
Array<String> versionParts;
pathParts[i - 1].Split('.', versionParts);
if (!versionParts.IsEmpty())
{
const String majorVersion = versionParts[0].TrimTrailing();
int32 versionNum;
StringUtils::Parse(*majorVersion, majorVersion.Length(), &versionNum);
if (Math::IsInRange(versionNum, GAME_BUILD_DOTNET_RUNTIME_MIN_VER, GAME_BUILD_DOTNET_RUNTIME_MAX_VER)) // Check for major part
version = majorVersion;
}
}
}
if (version.IsEmpty())
{
data.Error(TEXT("Failed to find supported .NET version for the current host platform."));
return true;
}
// Deploy runtime files
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
@@ -226,14 +253,14 @@ bool DeployDataStep::Perform(CookingData& data)
{
// AOT runtime files inside Engine Platform folder
packFolder /= TEXT("Dotnet");
dstDotnetLibs /= TEXT("lib/net8.0");
srcDotnetLibs = packFolder / TEXT("lib/net8.0");
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
srcDotnetLibs = packFolder / String::Format(TEXT("lib/net{}.0"), version);
}
else
{
// Runtime files inside Dotnet SDK folder but placed for AOT
dstDotnetLibs /= TEXT("lib/net8.0");
srcDotnetLibs /= TEXT("../lib/net8.0");
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
}
}
else
@@ -241,14 +268,14 @@ bool DeployDataStep::Perform(CookingData& data)
if (srcDotnetFromEngine)
{
// Runtime files inside Engine Platform folder
dstDotnetLibs /= TEXT("lib/net8.0");
srcDotnetLibs /= TEXT("lib/net8.0");
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
srcDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
}
else
{
// Runtime files inside Dotnet SDK folder
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
srcDotnetLibs /= TEXT("../lib/net8.0");
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
}
}
LOG(Info, "Copying .NET files from {} to {}", packFolder, dstDotnet);
@@ -273,6 +300,7 @@ bool DeployDataStep::Perform(CookingData& data)
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
DEPLOY_NATIVE_FILE("libSystem.Native.so");
DEPLOY_NATIVE_FILE("libSystem.Globalization.Native.so");
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
break;
case BuildPlatform::iOSARM64:
@@ -387,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

@@ -883,7 +883,7 @@ namespace FlaxEditor.CustomEditors
/// </summary>
protected virtual void ClearToken()
{
ParentEditor.ClearToken();
ParentEditor?.ClearToken();
}
}
}

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

@@ -9,6 +9,7 @@ using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Modules;
using FlaxEditor.Scripting;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
@@ -67,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
@@ -80,22 +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.ClearItemsSearch();
Editor.Instance.Windows.ContentWin.Select(prefab);
Editor.Instance.Windows.ContentWin.Open(Editor.Instance.Windows.ContentWin.View.Selection[0]);
};
// 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;
@@ -202,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

@@ -1,6 +1,7 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Linq;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.Surface;
using FlaxEngine;
@@ -35,6 +36,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
Values);
if (!parameters.Any())
group.Label("No parameters", TextAlignment.Center);
_parametersAdded = true;
}
}

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

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

View File

@@ -53,6 +53,9 @@ public class ModelPrefabEditor : GenericEditor
}
}
// Creates the import path UI
Utilities.Utils.CreateImportPathUI(layout, modelPrefab.ImportPath, false);
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
_reimportButton = button.Button;
_reimportButton.Clicked += OnReimport;

View File

@@ -117,6 +117,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
var data = SurfaceUtils.InitGraphParameters(parametersGroup);
SurfaceUtils.DisplayGraphParameters(group, data, ParameterGet, ParameterSet, Values, ParameterDefaultValue);
}
if (!parameters.Any())
groups.Label("No parameters", TextAlignment.Center);
}
/// <inheritdoc />

View File

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

View File

@@ -4,6 +4,7 @@ using System;
using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -122,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];
@@ -156,6 +159,17 @@ namespace FlaxEditor.CustomEditors.Editors
private Rectangle DropdownRect => new Rectangle(Width - DropdownIconSize - DropdownIconMargin, DropdownIconMargin, DropdownIconSize, DropdownIconSize);
public Action ShowPicker;
public Action<ContentItem> OnAssetDropped;
private DragItems _dragItems;
private DragHandlers _dragHandlers;
private bool _hasValidDragOver;
private Func<ContentItem, bool> _validate;
public void SetValidationMethod(Func<ContentItem, bool> validate)
{
_validate = validate;
}
public override void Draw()
{
@@ -164,6 +178,14 @@ namespace FlaxEditor.CustomEditors.Editors
var style = FlaxEngine.GUI.Style.Current;
var dropdownRect = DropdownRect;
Render2D.DrawSprite(style.ArrowDown, dropdownRect, Enabled ? (DropdownRect.Contains(PointFromWindow(RootWindow.MousePosition)) ? style.BorderSelected : style.Foreground) : style.ForegroundDisabled);
// Check if drag is over
if (IsDragOver && _hasValidDragOver)
{
var bounds = new Rectangle(Float2.Zero, Size);
Render2D.FillRectangle(bounds, style.Selection);
Render2D.DrawRectangle(bounds, style.SelectionBorder);
}
}
public override bool OnMouseDown(Float2 location, MouseButton button)
@@ -207,6 +229,68 @@ namespace FlaxEditor.CustomEditors.Editors
return result;
}
}
private DragDropEffect DragEffect => _hasValidDragOver ? DragDropEffect.Move : DragDropEffect.None;
/// <inheritdoc />
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
{
base.OnDragEnter(ref location, data);
// Ensure to have valid drag helpers (uses lazy init)
if (_dragItems == null)
_dragItems = new DragItems(ValidateDragAsset);
if (_dragHandlers == null)
{
_dragHandlers = new DragHandlers
{
_dragItems,
};
}
_hasValidDragOver = _dragHandlers.OnDragEnter(data) != DragDropEffect.None;
return DragEffect;
}
private bool ValidateDragAsset(ContentItem contentItem)
{
// Load or get asset
return _validate?.Invoke(contentItem) ?? false;
}
/// <inheritdoc />
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
{
base.OnDragMove(ref location, data);
return DragEffect;
}
/// <inheritdoc />
public override void OnDragLeave()
{
_hasValidDragOver = false;
_dragHandlers.OnDragLeave();
base.OnDragLeave();
}
/// <inheritdoc />
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
{
var result = DragEffect;
base.OnDragDrop(ref location, data);
if (_dragItems.HasValidDrag)
{
OnAssetDropped(_dragItems.Objects[0]);
}
return result;
}
}
private TextBoxWithPicker _textBox;
@@ -221,13 +305,21 @@ namespace FlaxEditor.CustomEditors.Editors
{
if (HasDifferentTypes)
return;
_validator = new AssetPickerValidator(ScriptType.Null);
_textBox = layout.Custom<TextBoxWithPicker>().CustomControl;
_textBox.ShowPicker = OnShowPicker;
_textBox.OnAssetDropped = OnItemDropped;
_textBox.EditEnd += OnEditEnd;
_validator = new AssetPickerValidator(ScriptType.Null);
_textBox.SetValidationMethod(_validator.IsValid);
AssetRefEditor.ApplyAssetReferenceAttribute(Values, out _, _validator);
}
private void OnItemDropped(ContentItem item)
{
SetPickerPath(item);
}
private void OnShowPicker()
{
if (_validator.AssetType != ScriptType.Null)
@@ -285,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

@@ -228,7 +228,6 @@ namespace FlaxEditor.CustomEditors.Editors
// Handle Sliding
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
{
// TODO: handle linked values
Float3 average = Float3.Zero;
for (int i = 0; i < Values.Count; i++)
{
@@ -251,12 +250,24 @@ namespace FlaxEditor.CustomEditors.Editors
for (int i = 0; i < Values.Count; i++)
{
var v = Values[i];
if (v is Vector3 asVector3)
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
else if (v is Float3 asFloat3)
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
else if (v is Double3 asDouble3)
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
if (LinkValues)
{
if (v is Vector3 asVector3)
v = asVector3 + new Vector3(newValue.X, newValue.Y, newValue.Z);
else if (v is Float3 asFloat3)
v = asFloat3 + new Float3(newValue.X, newValue.Y, newValue.Z);
else if (v is Double3 asDouble3)
v = asDouble3 + new Double3(newValue.X, newValue.Y, newValue.Z);
}
else
{
if (v is Vector3 asVector3)
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
else if (v is Float3 asFloat3)
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
else if (v is Double3 asDouble3)
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
}
newObjects[i] = v;
}
@@ -267,16 +278,27 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
// TODO: handle linked values
for (int i = 0; i < Values.Count; i++)
{
object v = Values[i];
if (v is Vector3 asVector3)
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
else if (v is Float3 asFloat3)
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
else if (v is Double3 asDouble3)
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
if (LinkValues)
{
if (v is Vector3 asVector3)
v = asVector3 + new Vector3(xValue, yValue, zValue);
else if (v is Float3 asFloat3)
v = asFloat3 + new Float3(xValue, yValue, zValue);
else if (v is Double3 asDouble3)
v = asDouble3 + new Double3(xValue, yValue, zValue);
}
else
{
if (v is Vector3 asVector3)
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
else if (v is Float3 asFloat3)
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
else if (v is Double3 asDouble3)
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
}
newObjects[i] = v;
}

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

@@ -550,7 +550,7 @@ int32 Editor::LoadProduct()
}
if (!FileSystem::FileExists(files[0]))
{
Platform::Fatal(TEXT("Cannot opoen selected project file because it doesn't exist."));
Platform::Fatal(TEXT("Cannot open selected project file because it doesn't exist."));
return -1;
}
projectPath = StringUtils::GetDirectoryName(files[0]);

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

@@ -1,7 +1,10 @@
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
#define USE_IS_FOREGROUND
#else
#endif
#if PLATFORM_SDL
#define USE_SDL_WORKAROUNDS
#endif
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
@@ -111,7 +114,7 @@ namespace FlaxEditor.GUI.ContextMenu
}
/// <summary>
/// Shows the empty menu popup o na screen.
/// Shows the empty menu popup on a screen.
/// </summary>
/// <param name="control">The target control.</param>
/// <param name="area">The target control area to cover.</param>
@@ -215,21 +218,27 @@ namespace FlaxEditor.GUI.ContextMenu
desc.AllowMaximize = false;
desc.AllowDragAndDrop = false;
desc.IsTopmost = true;
desc.IsRegularWindow = false;
desc.Type = WindowType.Popup;
desc.Parent = parentWin.Window;
desc.Title = "ContextMenu";
desc.HasSizingFrame = false;
OnWindowCreating(ref desc);
_window = Platform.CreateWindow(ref desc);
_window.GotFocus += OnWindowGotFocus;
_window.LostFocus += OnWindowLostFocus;
#if USE_IS_FOREGROUND && USE_SDL_WORKAROUNDS
// The focus between popup and parent windows doesn't change, force hide the popup when clicked on parent
parentWin.Window.MouseDown += OnWindowMouseDown;
_window.Closed += () => parentWin.Window.MouseDown -= OnWindowMouseDown;
#endif
// Attach to the window
_parentCM = parent as ContextMenuBase;
Parent = _window.GUI;
// Show
Visible = true;
if (_window == null)
return;
_window.Show();
PerformLayout();
_previouslyFocused = parentWin.FocusedControl;
@@ -378,6 +387,17 @@ namespace FlaxEditor.GUI.ContextMenu
}
}
#if USE_SDL_WORKAROUNDS
private void OnWindowGotFocus()
{
}
private void OnWindowMouseDown(ref Float2 mousePosition, MouseButton button, ref bool handled)
{
// The user clicked outside the popup window
Hide();
}
#else
private void OnWindowGotFocus()
{
var child = _childCM;
@@ -391,6 +411,7 @@ namespace FlaxEditor.GUI.ContextMenu
});
}
}
#endif
private void OnWindowLostFocus()
{
@@ -489,7 +510,12 @@ namespace FlaxEditor.GUI.ContextMenu
// Let root context menu to check if none of the popup windows
if (_parentCM == null && !IsForeground)
{
#if USE_SDL_WORKAROUNDS
if (!IsMouseOver)
Hide();
#else
Hide();
#endif
}
}
#endif

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

@@ -1,529 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI.Docking
{
/// <summary>
/// Helper class used to handle docking windows dragging and docking.
/// </summary>
public class DockHintWindow
{
private FloatWindowDockPanel _toMove;
private Float2 _dragOffset;
private Float2 _defaultWindowSize;
private Rectangle _rectDock;
private Rectangle _rectWindow;
private Float2 _mouse;
private DockState _toSet;
private DockPanel _toDock;
private bool _lateDragOffsetUpdate;
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
private DockHintWindow(FloatWindowDockPanel toMove)
{
_toMove = toMove;
_toSet = DockState.Float;
var window = toMove.Window.Window;
// Remove focus from drag target
_toMove.Focus();
_toMove.Defocus();
// Focus window
window.Focus();
// Check if window is maximized and restore window.
if (window.IsMaximized)
{
// Restore window and set position to mouse.
var mousePos = window.MousePosition;
var previousSize = window.Size;
window.Restore();
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
}
// Calculate dragging offset and move window to the destination position
var mouseScreenPosition = Platform.MousePosition;
// If the _toMove window was not focused when initializing this window, the result vector only contains zeros
// and to prevent a failure, we need to perform an update for the drag offset at later time which will be done in the OnMouseMove event handler.
if (mouseScreenPosition != Float2.Zero)
CalculateDragOffset(mouseScreenPosition);
else
_lateDragOffsetUpdate = true;
// Get initial size
_defaultWindowSize = window.Size;
// Init proxy window
Proxy.Init(ref _defaultWindowSize);
// Bind events
Proxy.Window.MouseUp += OnMouseUp;
Proxy.Window.MouseMove += OnMouseMove;
Proxy.Window.LostFocus += OnLostFocus;
// Start tracking mouse
Proxy.Window.StartTrackingMouse(false);
// Update window GUI
Proxy.Window.GUI.PerformLayout();
// Update rectangles
UpdateRects();
// Hide base window
window.Hide();
// Enable hit window presentation
Proxy.Window.RenderingEnabled = true;
Proxy.Window.Show();
Proxy.Window.Focus();
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose()
{
// End tracking mouse
Proxy.Window.EndTrackingMouse();
// Disable rendering
Proxy.Window.RenderingEnabled = false;
// Unbind events
Proxy.Window.MouseUp -= OnMouseUp;
Proxy.Window.MouseMove -= OnMouseMove;
Proxy.Window.LostFocus -= OnLostFocus;
// Hide the proxy
Proxy.Hide();
if (_toMove == null)
return;
// Check if window won't be docked
if (_toSet == DockState.Float)
{
var window = _toMove.Window?.Window;
if (window == null)
return;
var mouse = Platform.MousePosition;
// Move base window
window.Position = mouse - _dragOffset;
// Show base window
window.Show();
}
else
{
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
// Check if window has only single tab
if (hasNoChildPanels && _toMove.TabsCount == 1)
{
// Dock window
_toMove.GetTab(0).Show(_toSet, _toDock);
}
// Check if dock as tab and has no child panels
else if (hasNoChildPanels && _toSet == DockState.DockFill)
{
// Dock all tabs
while (_toMove.TabsCount > 0)
{
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
}
}
else
{
var selectedTab = _toMove.SelectedTab;
// Dock the first tab into the target location
var firstTab = _toMove.GetTab(0);
firstTab.Show(_toSet, _toDock);
// Dock rest of the tabs
while (_toMove.TabsCount > 0)
{
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
}
// Keep selected tab being selected
selectedTab?.SelectTab();
}
// Focus target window
_toDock.Root.Focus();
}
_toMove = null;
}
/// <summary>
/// Creates the new dragging hit window.
/// </summary>
/// <param name="toMove">Floating dock panel to move.</param>
/// <returns>The dock hint window object.</returns>
public static DockHintWindow Create(FloatWindowDockPanel toMove)
{
if (toMove == null)
throw new ArgumentNullException();
return new DockHintWindow(toMove);
}
/// <summary>
/// Creates the new dragging hit window.
/// </summary>
/// <param name="toMove">Dock window to move.</param>
/// <returns>The dock hint window object.</returns>
public static DockHintWindow Create(DockWindow toMove)
{
if (toMove == null)
throw new ArgumentNullException();
// Show floating
toMove.ShowFloating();
// Move window to the mouse position (with some offset for caption bar)
var window = (WindowRootControl)toMove.Root;
var mouse = Platform.MousePosition;
window.Window.Position = mouse - new Float2(8, 8);
// Get floating panel
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
return new DockHintWindow(floatingPanelToMove);
}
/// <summary>
/// Calculates window rectangle in the dock window.
/// </summary>
/// <param name="state">Window dock state.</param>
/// <param name="rect">Dock panel rectangle.</param>
/// <returns>Calculated window rectangle.</returns>
public static Rectangle CalculateDockRect(DockState state, ref Rectangle rect)
{
Rectangle result = rect;
switch (state)
{
case DockState.DockFill:
result.Location.Y += DockPanel.DefaultHeaderHeight;
result.Size.Y -= DockPanel.DefaultHeaderHeight;
break;
case DockState.DockTop:
result.Size.Y *= DockPanel.DefaultSplitterValue;
break;
case DockState.DockLeft:
result.Size.X *= DockPanel.DefaultSplitterValue;
break;
case DockState.DockBottom:
result.Location.Y += result.Size.Y * (1 - DockPanel.DefaultSplitterValue);
result.Size.Y *= DockPanel.DefaultSplitterValue;
break;
case DockState.DockRight:
result.Location.X += result.Size.X * (1 - DockPanel.DefaultSplitterValue);
result.Size.X *= DockPanel.DefaultSplitterValue;
break;
}
return result;
}
private void CalculateDragOffset(Float2 mouseScreenPosition)
{
var baseWinPos = _toMove.Window.Window.Position;
_dragOffset = mouseScreenPosition - baseWinPos;
}
private void UpdateRects()
{
// Cache mouse position
_mouse = Platform.MousePosition;
// Check intersection with any dock panel
var uiMouse = _mouse;
_toDock = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove);
// Check dock state to use
bool showProxyHints = _toDock != null;
bool showBorderHints = showProxyHints;
bool showCenterHint = showProxyHints;
if (showProxyHints)
{
// If moved window has not only tabs but also child panels disable docking as tab
if (_toMove.ChildPanelsCount > 0)
showCenterHint = false;
// Disable docking windows with one or more dock panels inside
if (_toMove.ChildPanelsCount > 0)
showBorderHints = false;
// Get dock area
_rectDock = _toDock.DockAreaBounds;
// Cache dock rectangles
var size = _rectDock.Size;
var offset = _rectDock.Location;
var borderMargin = 4.0f;
var hintWindowsSize = Proxy.HintWindowsSize * Platform.DpiScale;
var hintWindowsSize2 = hintWindowsSize * 0.5f;
var centerX = size.X * 0.5f;
var centerY = size.Y * 0.5f;
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
// Hit test
DockState toSet = DockState.Float;
if (showBorderHints)
{
if (_rUpper.Contains(_mouse))
toSet = DockState.DockTop;
else if (_rBottom.Contains(_mouse))
toSet = DockState.DockBottom;
else if (_rLeft.Contains(_mouse))
toSet = DockState.DockLeft;
else if (_rRight.Contains(_mouse))
toSet = DockState.DockRight;
}
if (showCenterHint && _rCenter.Contains(_mouse))
toSet = DockState.DockFill;
_toSet = toSet;
// Show proxy hint windows
Proxy.Down.Position = _rBottom.Location;
Proxy.Left.Position = _rLeft.Location;
Proxy.Right.Position = _rRight.Location;
Proxy.Up.Position = _rUpper.Location;
Proxy.Center.Position = _rCenter.Location;
}
else
{
_toSet = DockState.Float;
}
// Update proxy hint windows visibility
Proxy.Down.IsVisible = showProxyHints & showBorderHints;
Proxy.Left.IsVisible = showProxyHints & showBorderHints;
Proxy.Right.IsVisible = showProxyHints & showBorderHints;
Proxy.Up.IsVisible = showProxyHints & showBorderHints;
Proxy.Center.IsVisible = showProxyHints & showCenterHint;
// Calculate proxy/dock/window rectangles
if (_toDock == null)
{
// Floating window over nothing
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
}
else
{
if (_toSet == DockState.Float)
{
// Floating window over dock panel
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
}
else
{
// Use only part of the dock panel to show hint
_rectWindow = CalculateDockRect(_toSet, ref _rectDock);
}
}
// Update proxy window
Proxy.Window.ClientBounds = _rectWindow;
}
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
{
if (button == MouseButton.Left)
{
Dispose();
}
}
private void OnMouseMove(ref Float2 mousePos)
{
// Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window
if (_lateDragOffsetUpdate)
{
// Calculate dragging offset and move window to the destination position
CalculateDragOffset(mousePos);
// Reset state
_lateDragOffsetUpdate = false;
}
UpdateRects();
}
private void OnLostFocus()
{
Dispose();
}
/// <summary>
/// Contains helper proxy windows shared across docking panels. They are used to visualize docking window locations.
/// </summary>
public static class Proxy
{
/// <summary>
/// The drag proxy window.
/// </summary>
public static Window Window;
/// <summary>
/// The left hint proxy window.
/// </summary>
public static Window Left;
/// <summary>
/// The right hint proxy window.
/// </summary>
public static Window Right;
/// <summary>
/// The up hint proxy window.
/// </summary>
public static Window Up;
/// <summary>
/// The down hint proxy window.
/// </summary>
public static Window Down;
/// <summary>
/// The center hint proxy window.
/// </summary>
public static Window Center;
/// <summary>
/// The hint windows size.
/// </summary>
public const float HintWindowsSize = 32.0f;
/// <summary>
/// Initializes the hit proxy windows. Those windows are used to indicate drag target areas (left, right, top, bottom, etc.).
/// </summary>
public static void InitHitProxy()
{
CreateProxy(ref Left, "DockHint.Left");
CreateProxy(ref Right, "DockHint.Right");
CreateProxy(ref Up, "DockHint.Up");
CreateProxy(ref Down, "DockHint.Down");
CreateProxy(ref Center, "DockHint.Center");
}
/// <summary>
/// Initializes the hint window.
/// </summary>
/// <param name="initSize">Initial size of the proxy window.</param>
public static void Init(ref Float2 initSize)
{
if (Window == null)
{
var settings = CreateWindowSettings.Default;
settings.Title = "DockHint.Window";
settings.Size = initSize;
settings.AllowInput = true;
settings.AllowMaximize = false;
settings.AllowMinimize = false;
settings.HasBorder = false;
settings.HasSizingFrame = false;
settings.IsRegularWindow = false;
settings.SupportsTransparency = true;
settings.ShowInTaskbar = false;
settings.ShowAfterFirstPaint = false;
settings.IsTopmost = true;
Window = Platform.CreateWindow(ref settings);
Window.Opacity = 0.6f;
Window.GUI.BackgroundColor = Style.Current.DragWindow;
}
else
{
// Resize proxy
Window.ClientSize = initSize;
}
InitHitProxy();
}
private static void CreateProxy(ref Window win, string name)
{
if (win != null)
return;
var settings = CreateWindowSettings.Default;
settings.Title = name;
settings.Size = new Float2(HintWindowsSize * Platform.DpiScale);
settings.AllowInput = false;
settings.AllowMaximize = false;
settings.AllowMinimize = false;
settings.HasBorder = false;
settings.HasSizingFrame = false;
settings.IsRegularWindow = false;
settings.SupportsTransparency = true;
settings.ShowInTaskbar = false;
settings.ActivateWhenFirstShown = false;
settings.IsTopmost = true;
settings.ShowAfterFirstPaint = false;
win = Platform.CreateWindow(ref settings);
win.Opacity = 0.6f;
win.GUI.BackgroundColor = Style.Current.DragWindow;
}
/// <summary>
/// Hides proxy windows.
/// </summary>
public static void Hide()
{
HideProxy(ref Window);
HideProxy(ref Left);
HideProxy(ref Right);
HideProxy(ref Up);
HideProxy(ref Down);
HideProxy(ref Center);
}
private static void HideProxy(ref Window win)
{
if (win)
{
win.Hide();
}
}
/// <summary>
/// Releases proxy data and windows.
/// </summary>
public static void Dispose()
{
DisposeProxy(ref Window);
DisposeProxy(ref Left);
DisposeProxy(ref Right);
DisposeProxy(ref Up);
DisposeProxy(ref Down);
DisposeProxy(ref Center);
}
private static void DisposeProxy(ref Window win)
{
if (win)
{
win.Close(ClosingReason.User);
win = null;
}
}
}
}
}

View File

@@ -49,6 +49,11 @@ namespace FlaxEditor.GUI.Docking
/// The mouse position.
/// </summary>
public Float2 MousePosition = Float2.Minimum;
/// <summary>
/// The mouse position.
/// </summary>
public Float2 MouseStartPosition = Float2.Minimum;
/// <summary>
/// The start drag asynchronous window.
@@ -165,7 +170,7 @@ namespace FlaxEditor.GUI.Docking
if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating)
{
// Create docking hint window but in an async manner
DockHintWindow.Create(_panel as FloatWindowDockPanel);
WindowDragHelper.StartDragging(_panel as FloatWindowDockPanel);
}
else
{
@@ -176,7 +181,7 @@ namespace FlaxEditor.GUI.Docking
_panel.SelectTab(index - 1);
// Create docking hint window
DockHintWindow.Create(win);
WindowDragHelper.StartDragging(win, _panel.RootWindow.Window);
}
}
}
@@ -355,6 +360,7 @@ namespace FlaxEditor.GUI.Docking
if (IsSingleFloatingWindow)
return base.OnMouseDown(location, button);
MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross);
MouseStartPosition = location;
// Check buttons
if (button == MouseButton.Left)
@@ -441,6 +447,20 @@ namespace FlaxEditor.GUI.Docking
StartDrag(MouseDownWindow);
MouseDownWindow = null;
}
// Check if single tab is tried to be moved
else if (MouseDownWindow != null && _panel.TabsCount <= 1)
{
if ((MousePosition - MouseStartPosition).Length > 3)
{
// Clear flag
IsMouseLeftButtonDown = false;
// Check tab under the mouse
if (!IsMouseDownOverCross && MouseDownWindow != null)
StartDrag(MouseDownWindow);
MouseDownWindow = null;
}
}
// Check if has more than one tab to change order
else if (MouseDownWindow != null && _panel.TabsCount > 1)
{

View File

@@ -182,6 +182,25 @@ namespace FlaxEditor.GUI.Docking
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
/// <param name="position">Window location.</param>
public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent)
{
CreateFloating(location, size, position, true);
}
/// <summary>
/// Creates the window in a floating state.
/// </summary>
public void CreateFloating()
{
CreateFloating(Float2.Zero, Float2.Zero);
}
/// <summary>
/// Creates the window in a floating state.
/// </summary>
/// <param name="location">Window location.</param>
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
/// <param name="position">Window location.</param>
/// <param name="showWindow">Window visibility.</param>
public void CreateFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent, bool showWindow = false)
{
Undock();
@@ -199,14 +218,17 @@ namespace FlaxEditor.GUI.Docking
windowGUI.UnlockChildrenRecursive();
windowGUI.PerformLayout();
// Show
window.Show();
window.BringToFront();
window.Focus();
OnShow();
if (showWindow)
{
// Show
window.Show();
window.BringToFront();
window.Focus();
OnShow();
// Perform layout again
windowGUI.PerformLayout();
// Perform layout again
windowGUI.PerformLayout();
}
}
/// <summary>
@@ -464,7 +486,7 @@ namespace FlaxEditor.GUI.Docking
{
base.Focus();
SelectTab();
SelectTab(false);
BringToFront();
}

View File

@@ -52,7 +52,7 @@ namespace FlaxEditor.GUI.Docking
return;
// Create docking hint window
DockHintWindow.Create(this);
WindowDragHelper.StartDragging(this);
}
/// <summary>
@@ -75,14 +75,14 @@ namespace FlaxEditor.GUI.Docking
settings.MaximumSize = Float2.Zero; // Unlimited size
settings.Fullscreen = false;
settings.HasBorder = true;
settings.SupportsTransparency = false;
settings.SupportsTransparency = true;
settings.ActivateWhenFirstShown = true;
settings.AllowInput = true;
settings.AllowMinimize = true;
settings.AllowMaximize = true;
settings.AllowDragAndDrop = true;
settings.IsTopmost = false;
settings.IsRegularWindow = true;
settings.Type = WindowType.Regular;
settings.HasSizingFrame = true;
settings.ShowAfterFirstPaint = false;
settings.ShowInTaskbar = true;

View File

@@ -81,7 +81,6 @@ namespace FlaxEditor.GUI.Docking
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
{
// Check all floating windows
// TODO: gather windows order and take it into account when performing test
for (int i = 0; i < FloatingPanels.Count; i++)
{
var win = FloatingPanels[i];
@@ -94,9 +93,44 @@ namespace FlaxEditor.GUI.Docking
}
// Base
//if (!Root?.RootWindow.Window.IsFocused ?? false)
// return null;
return base.HitTest(ref position);
}
/// <summary>
/// Performs hit test over dock panel.
/// </summary>
/// <param name="position">Window space position to test.</param>
/// <param name="excluded">Floating window to omit during searching (and all docked to that one).</param>
/// <param name="hitResults">Results of the hit test</param>
/// <returns>True if any dock panels were hit, otherwise false.</returns>
public bool HitTest(ref Float2 position, FloatWindowDockPanel excluded, out DockPanel[] hitResults)
{
// Check all floating windows
List<DockPanel> results = new(FloatingPanels.Count);
for (int i = 0; i < FloatingPanels.Count; i++)
{
var win = FloatingPanels[i];
if (win.Visible && win != excluded)
{
var result = win.HitTest(ref position);
if (result != null)
results.Add(result);
}
}
// Base
//if (!Root?.RootWindow.Window.IsFocused ?? false)
// return null;
var baseResult = base.HitTest(ref position);
if (baseResult != null)
results.Add(baseResult);
hitResults = results.ToArray();
return hitResults.Length > 0;
}
internal void LinkWindow(DockWindow window)
{
// Add to the windows list

View File

@@ -0,0 +1,448 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI.Docking
{
/// <summary>
/// Helper class used to handle docking windows dragging and docking.
/// </summary>
public class WindowDragHelper
{
private FloatWindowDockPanel _toMove;
private Float2 _dragOffset;
private Rectangle _rectDock;
private Float2 _mouse;
private DockState _toSet;
private DockPanel _toDock;
private Window _dragSourceWindow;
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
private Control _dockHintDown, _dockHintUp, _dockHintLeft, _dockHintRight, _dockHintCenter;
/// <summary>
/// The hint control size.
/// </summary>
public const float HintControlSize = 32.0f;
/// <summary>
/// The opacity of the dragged window when hint controls are shown.
/// </summary>
public const float DragWindowOpacity = 0.4f;
private WindowDragHelper(FloatWindowDockPanel toMove, Window dragSourceWindow)
{
_toMove = toMove;
_toSet = DockState.Float;
var window = toMove.Window.Window;
// Check if window is maximized and restore window.
if (window.IsMaximized)
{
// Restore window and set position to mouse.
var mousePos = window.MousePosition;
var previousSize = window.Size;
window.Restore();
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
}
// Bind events
FlaxEngine.Scripting.Update += OnUpdate;
window.MouseUp += OnMouseUp;
// Update rectangles
UpdateRects(Platform.MousePosition);
_dragSourceWindow = dragSourceWindow;
if (_dragSourceWindow != null) // Detaching a tab from existing window
{
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
// TODO: when detaching tab in floating window (not main window), the drag source window is still main window?
var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow;
window.DoDragDrop(window.Title, _dragOffset, dragSourceWindowWayland);
_dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows
}
else
{
_dragOffset = window.MousePosition;
window.DoDragDrop(window.Title, _dragOffset, window);
}
// Ensure the dragged window stays on top of every other window
window.IsAlwaysOnTop = true;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose()
{
var window = _toMove?.Window?.Window;
// Unbind events
FlaxEngine.Scripting.Update -= OnUpdate;
if (window != null)
window.MouseUp -= OnMouseUp;
if (_dragSourceWindow != null)
_dragSourceWindow.MouseUp -= OnMouseUp;
RemoveDockHints();
if (_toMove == null)
return;
if (window != null)
{
window.Opacity = 1.0f;
window.IsAlwaysOnTop = false;
window.BringToFront();
}
// Check if window won't be docked
if (_toSet == DockState.Float)
{
if (window == null)
return;
// Show base window
window.Show();
}
else
{
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
// Check if window has only single tab
if (hasNoChildPanels && _toMove.TabsCount == 1)
{
// Dock window
_toMove.GetTab(0).Show(_toSet, _toDock);
}
// Check if dock as tab and has no child panels
else if (hasNoChildPanels && _toSet == DockState.DockFill)
{
// Dock all tabs
while (_toMove.TabsCount > 0)
{
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
}
}
else
{
var selectedTab = _toMove.SelectedTab;
// Dock the first tab into the target location
if (_toMove.TabsCount > 0)
{
var firstTab = _toMove.GetTab(0);
firstTab.Show(_toSet, _toDock);
// Dock rest of the tabs
while (_toMove.TabsCount > 0)
{
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
}
}
// Keep selected tab being selected
selectedTab?.SelectTab();
}
// Focus target window
_toDock.Root.Focus();
}
_toMove = null;
}
/// <summary>
/// Start dragging a floating dock panel.
/// </summary>
/// <param name="toMove">Floating dock panel to move.</param>
/// <returns>The window drag helper object.</returns>
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove)
{
if (toMove == null)
throw new ArgumentNullException();
return new WindowDragHelper(toMove, null);
}
/// <summary>
/// Start dragging a docked panel into a floating window.
/// </summary>
/// <param name="toMove">Dock window to move.</param>
/// <param name="dragSourceWindow">The window where dragging started from.</param>
/// <returns>The window drag helper object.</returns>
public static WindowDragHelper StartDragging(DockWindow toMove, Window dragSourceWindow)
{
if (toMove == null)
throw new ArgumentNullException();
// Create floating window
toMove.CreateFloating();
// Get floating panel
var window = (WindowRootControl)toMove.Root;
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
return new WindowDragHelper(floatingPanelToMove, dragSourceWindow);
}
private void AddDockHints()
{
if (_toDock == null)
return;
if (_toDock.RootWindow.Window != _dragSourceWindow)
_toDock.RootWindow.Window.MouseUp += OnMouseUp;
_dockHintDown = AddHintControl(new Float2(0.5f, 1));
_dockHintUp = AddHintControl(new Float2(0.5f, 0));
_dockHintLeft = AddHintControl(new Float2(0, 0.5f));
_dockHintRight = AddHintControl(new Float2(1, 0.5f));
_dockHintCenter = AddHintControl(new Float2(0.5f, 0.5f));
Control AddHintControl(Float2 pivot)
{
Control hintControl = _toDock.AddChild<Control>();
hintControl.AnchorPreset = AnchorPresets.StretchAll;
hintControl.Offsets = Margin.Zero;
hintControl.Size = new Float2(HintControlSize);
hintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
hintControl.Pivot = pivot;
hintControl.PivotRelative = true;
return hintControl;
}
}
private void RemoveDockHints()
{
if (_toDock == null)
return;
if (_toDock.RootWindow.Window != _dragSourceWindow)
_toDock.RootWindow.Window.MouseUp -= OnMouseUp;
_dockHintDown?.Parent.RemoveChild(_dockHintDown);
_dockHintUp?.Parent.RemoveChild(_dockHintUp);
_dockHintLeft?.Parent.RemoveChild(_dockHintLeft);
_dockHintRight?.Parent.RemoveChild(_dockHintRight);
_dockHintCenter?.Parent.RemoveChild(_dockHintCenter);
_dockHintDown = _dockHintUp = _dockHintLeft = _dockHintRight = _dockHintCenter = null;
}
private void UpdateRects(Float2 mousePos)
{
// Cache mouse position
_mouse = mousePos;
// Check intersection with any dock panel
DockPanel dockPanel = null;
if (_toMove.MasterPanel.HitTest(ref _mouse, _toMove, out var hitResults))
{
dockPanel = hitResults[0];
// Prefer panel which currently has focus
foreach (var hit in hitResults)
{
if (hit.RootWindow.Window.IsFocused)
{
dockPanel = hit;
break;
}
}
// Prefer panel in the same window we hit earlier
if (dockPanel?.RootWindow != _toDock?.RootWindow)
{
foreach (var hit in hitResults)
{
if (hit.RootWindow == _toDock?.RootWindow)
{
dockPanel = _toDock;
break;
}
}
}
}
if (dockPanel != _toDock)
{
RemoveDockHints();
_toDock = dockPanel;
AddDockHints();
// Make sure the all the dock hint areas are not under other windows
_toDock?.RootWindow.Window.BringToFront();
//_toDock?.RootWindow.Window.Focus();
// Make the dragged window transparent when dock hints are visible
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
}
// Check dock state to use
bool showProxyHints = _toDock != null;
bool showBorderHints = showProxyHints;
bool showCenterHint = showProxyHints;
Control hoveredHintControl = null;
Float2 hoveredSizeOverride = Float2.Zero;
if (showProxyHints)
{
// If moved window has not only tabs but also child panels disable docking as tab
if (_toMove.ChildPanelsCount > 0)
showCenterHint = false;
// Disable docking windows with one or more dock panels inside
if (_toMove.ChildPanelsCount > 0)
showBorderHints = false;
// Get dock area
_rectDock = _toDock.DockAreaBounds;
// Cache dock rectangles
var size = _rectDock.Size / Platform.DpiScale;
var offset = _toDock.PointFromScreen(_rectDock.Location);
var borderMargin = 4.0f;
var hintWindowsSize = HintControlSize;
var hintWindowsSize2 = hintWindowsSize * 0.5f;
var hintPreviewSize = new Float2(Math.Max(HintControlSize * 2, size.X * 0.5f), Math.Max(HintControlSize * 2, size.Y * 0.5f));
var centerX = size.X * 0.5f;
var centerY = size.Y * 0.5f;
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
// Hit test, and calculate the approximation for filled area when hovered over the hint
DockState toSet = DockState.Float;
if (showBorderHints)
{
if (_rUpper.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockTop;
hoveredHintControl = _dockHintUp;
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
}
else if (_rBottom.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockBottom;
hoveredHintControl = _dockHintDown;
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
}
else if (_rLeft.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockLeft;
hoveredHintControl = _dockHintLeft;
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
}
else if (_rRight.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockRight;
hoveredHintControl = _dockHintRight;
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
}
}
if (showCenterHint && _rCenter.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockFill;
hoveredHintControl = _dockHintCenter;
hoveredSizeOverride = new Float2(size.X, size.Y);
}
_toSet = toSet;
}
else
{
_toSet = DockState.Float;
}
// Update sizes and opacity of hint controls
if (_toDock != null)
{
if (hoveredHintControl != _dockHintDown)
{
_dockHintDown.Size = new Float2(HintControlSize);
_dockHintDown.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintLeft)
{
_dockHintLeft.Size = new Float2(HintControlSize);
_dockHintLeft.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintRight)
{
_dockHintRight.Size = new Float2(HintControlSize);
_dockHintRight.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintUp)
{
_dockHintUp.Size = new Float2(HintControlSize);
_dockHintUp.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintCenter)
{
_dockHintCenter.Size = new Float2(HintControlSize);
_dockHintCenter.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (_toSet != DockState.Float)
{
if (hoveredHintControl != null)
{
hoveredHintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(1.0f);
hoveredHintControl.Size = hoveredSizeOverride;
}
}
}
// Update hint controls visibility and location
if (showProxyHints)
{
if (hoveredHintControl != _dockHintDown)
_dockHintDown.Location = _rBottom.Location;
if (hoveredHintControl != _dockHintLeft)
_dockHintLeft.Location = _rLeft.Location;
if (hoveredHintControl != _dockHintRight)
_dockHintRight.Location = _rRight.Location;
if (hoveredHintControl != _dockHintUp)
_dockHintUp.Location = _rUpper.Location;
if (hoveredHintControl != _dockHintCenter)
_dockHintCenter.Location = _rCenter.Location;
_dockHintDown.Visible = showProxyHints & showBorderHints;
_dockHintLeft.Visible = showProxyHints & showBorderHints;
_dockHintRight.Visible = showProxyHints & showBorderHints;
_dockHintUp.Visible = showProxyHints & showBorderHints;
_dockHintCenter.Visible = showProxyHints & showCenterHint;
}
}
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
{
if (button == MouseButton.Left)
Dispose();
}
private void OnUpdate()
{
var mousePos = Platform.MousePosition;
if (_mouse != mousePos)
OnMouseMove(mousePos);
}
private void OnMouseMove(Float2 mousePos)
{
if (_dragSourceWindow != null)
_toMove.Window.Window.Position = mousePos - _dragOffset;
UpdateRects(mousePos);
}
}
}

View File

@@ -266,6 +266,7 @@ namespace FlaxEditor.GUI.Input
return base.OnMouseDown(location, button);
}
#if !PLATFORM_SDL
/// <inheritdoc />
public override void OnMouseMove(Float2 location)
{
@@ -292,13 +293,45 @@ namespace FlaxEditor.GUI.Input
base.OnMouseMove(location);
}
#else
/// <inheritdoc />
public override void OnMouseMoveRelative(Float2 mouseMotion)
{
var location = Root.TrackingMouseOffset;
if (_isSliding)
{
// Update sliding
ApplySliding(Root.TrackingMouseOffset.X * _slideSpeed);
return;
}
// Update cursor type so user knows they can slide value
if (CanUseSliding && SlideRect.Contains(location) && !_isSliding)
{
Cursor = CursorType.SizeWE;
_cursorChanged = true;
}
else if (_cursorChanged && !_isSliding)
{
Cursor = CursorType.Default;
_cursorChanged = false;
}
base.OnMouseMoveRelative(mouseMotion);
}
#endif
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isSliding)
{
#if !PLATFORM_SDL
// End sliding and return mouse to original location
RootWindow.MousePosition = _mouseClickedPosition;
#endif
EndSliding();
return true;
}

View File

@@ -12,7 +12,7 @@ namespace FlaxEditor.GUI
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public sealed class MainMenu : ContainerControl
{
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
private bool _useCustomWindowSystem;
private Image _icon;
private Label _title;
@@ -67,7 +67,7 @@ namespace FlaxEditor.GUI
AutoFocus = false;
AnchorPreset = AnchorPresets.HorizontalStretchTop;
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
_useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
if (_useCustomWindowSystem)
{
@@ -84,13 +84,15 @@ namespace FlaxEditor.GUI
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
var driver = Platform.DisplayServer;
_icon = new Image
{
Margin = new Margin(6, 6, 6, 6),
Brush = new TextureBrush(windowIcon),
Color = Style.Current.Foreground,
KeepAspectRatio = false,
TooltipText = string.Format("{0}\nVersion {1}\nConfiguration {3}\nGraphics {2}", _window.Title, Globals.EngineVersion, GPUDevice.Instance.RendererType, configuration),
TooltipText = string.Format("{0}\nVersion {1}\nConfiguration {3}\nGraphics {2} {4}", _window.Title, Globals.EngineVersion, GPUDevice.Instance.RendererType, configuration, driver),
Parent = this,
};
@@ -166,7 +168,7 @@ namespace FlaxEditor.GUI
}
}
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
/// <inheritdoc />
public override void Update(float deltaTime)
{
@@ -291,7 +293,7 @@ namespace FlaxEditor.GUI
if (base.OnMouseDoubleClick(location, button))
return true;
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
var child = GetChildAtRecursive(location);
if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
{
@@ -321,7 +323,7 @@ namespace FlaxEditor.GUI
{
float x = 0;
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
if (_useCustomWindowSystem)
{
// Icon
@@ -349,7 +351,7 @@ namespace FlaxEditor.GUI
}
}
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
if (_useCustomWindowSystem)
{
// Buttons
@@ -367,7 +369,7 @@ namespace FlaxEditor.GUI
#endif
}
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
/// <inheritdoc />
public override void OnDestroy()
{

View File

@@ -42,7 +42,7 @@ namespace FlaxEditor.GUI
Text = text;
var style = Style.Current;
#if PLATFORM_WINDOWS
#if PLATFORM_WINDOWS || PLATFORM_SDL
if (Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
{
BackgroundColorMouseOver = style.BackgroundHighlighted;

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

@@ -169,12 +169,12 @@ namespace FlaxEditor.Gizmo
closestIntersection = intersection;
}
/*// Center
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
// Center
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
{
_activeAxis = Axis.Center;
closestIntersection = intersection;
}*/
}
break;
}

View File

@@ -20,7 +20,7 @@ namespace FlaxEditor.Gizmo
/// <summary>
/// Offset to move axis away from center
/// </summary>
private const float AxisOffset = 0.8f;
private const float AxisOffset = 1.2f;
/// <summary>
/// How thick the axis should be

View File

@@ -501,7 +501,7 @@ namespace FlaxEditor.Gizmo
_scaleDelta = Vector3.Zero;
if (ActiveAxis == Axis.Center)
scaleDelta = new Vector3(scaleDelta.AvgValue);
scaleDelta = new Vector3(scaleDelta.ValuesSum);
}
// Apply transformation (but to the parents, not whole selection pool)

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Gizmo;
@@ -149,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;
@@ -563,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
@@ -640,14 +642,103 @@ namespace FlaxEditor
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
// TODO: draw anchors
// Draw pivot
var pivotSize = 8.0f;
if (viewScale < 0.7f)
pivotSize *= viewScale;
var pivotX = Mathf.Remap(control.Pivot.X, 0, 1, bounds.Location.X, bounds.Location.X + bounds.Width);
var pivotY = Mathf.Remap(control.Pivot.Y, 0, 1, bounds.Location.Y, bounds.Location.Y + bounds.Height);
var pivotLoc = control.PointToParent(this, new Float2(pivotX, pivotY));
var pivotRect = new Rectangle(pivotLoc - pivotSize * 0.5f, new Float2(pivotSize));
var pivotColor = options.UIPivotColor;
Render2D.FillRectangle(pivotRect, pivotColor);
// Draw anchors
var controlParent = control.Parent;
if (controlParent != null)
{
var parentBounds = controlParent.EditorBounds;
var anchorMin = control.AnchorMin;
var anchorMax = control.AnchorMax;
var newMinX = Mathf.Remap(anchorMin.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
var newMinY = Mathf.Remap(anchorMin.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
var newMaxX = Mathf.Remap(anchorMax.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
var newMaxY = Mathf.Remap(anchorMax.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
var anchorUpperLeft = controlParent.PointToParent(this, new Float2(newMinX, newMinY));
var anchorUpperRight = controlParent.PointToParent(this, new Float2(newMaxX, newMinY));
var anchorLowerLeft = controlParent.PointToParent(this, new Float2(newMinX, newMaxY));
var anchorLowerRight = controlParent.PointToParent(this, new Float2(newMaxX, newMaxY));
var anchorRectSize = 8.0f;
if (viewScale < 0.7f)
anchorRectSize *= viewScale;
// Make anchor rects and rotate if parent is rotated.
var parentRotation = controlParent.Rotation * Mathf.DegreesToRadians;
var rect1Axis = new Float2(-1, -1);
var rect1 = new Rectangle(anchorUpperLeft +
new Float2(anchorRectSize * rect1Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect1Axis.Y * Mathf.Sin(parentRotation),
anchorRectSize * rect1Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect1Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
var rect2Axis = new Float2(1, -1);
var rect2 = new Rectangle(anchorUpperRight +
new Float2(anchorRectSize * rect2Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect2Axis.Y * Mathf.Sin(parentRotation),
anchorRectSize * rect2Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect2Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
var rect3Axis = new Float2(-1, 1);
var rect3 = new Rectangle(anchorLowerLeft +
new Float2(anchorRectSize * rect3Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect3Axis.Y * Mathf.Sin(parentRotation),
anchorRectSize * rect3Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect3Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
var rect4Axis = new Float2(1, 1);
var rect4 = new Rectangle(anchorLowerRight +
new Float2(anchorRectSize * rect4Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect4Axis.Y * Mathf.Sin(parentRotation),
anchorRectSize * rect4Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect4Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
var rectColor = options.UIAnchorColor;
Render2D.DrawLine(anchorUpperLeft, anchorUpperRight, rectColor);
Render2D.DrawLine(anchorUpperRight, anchorLowerRight, rectColor);
Render2D.DrawLine(anchorLowerRight, anchorLowerLeft, rectColor);
Render2D.DrawLine(anchorLowerLeft, anchorUpperLeft, rectColor);
Render2D.FillRectangle(rect1, rectColor);
Render2D.FillRectangle(rect2, rectColor);
Render2D.FillRectangle(rect3, rectColor);
Render2D.FillRectangle(rect4, rectColor);
}
}
}
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
{
var style = Style.Current;
var rect = new Rectangle((pos + resizeAxis * 10 * scale) - size * 0.5f, size);
var control = uiControl.Control;
var rotation = control.Rotation;
var rotationInRadians = rotation * Mathf.DegreesToRadians;
var rect = new Rectangle((pos +
new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 10 * scale) - size * 0.5f,
size);
// Find more correct cursor at different angles
var unwindRotation = Mathf.UnwindDegrees(rotation);
if (unwindRotation is (>= 45 and < 135) or (> -135 and <= -45) )
{
switch (cursor)
{
case CursorType.SizeNESW:
cursor = CursorType.SizeNWSE;
break;
case CursorType.SizeNS:
cursor = CursorType.SizeWE;
break;
case CursorType.SizeNWSE:
cursor = CursorType.SizeNESW;
break;
case CursorType.SizeWE:
cursor = CursorType.SizeNS;
break;
default: break;
}
}
if (rect.Contains(ref mousePos))
{
Render2D.FillRectangle(rect, style.Foreground);
@@ -684,16 +775,15 @@ namespace FlaxEditor
private bool RayCastControl(ref Float2 location, out Control hit)
{
#if false
// Raycast only controls with content (eg. skips transparent panels)
return RayCastChildren(ref location, out hit);
#else
// Find any control under mouse (hierarchical)
hit = GetChildAtRecursive(location);
// First, raycast only controls with content (eg. skips transparent panels)
RayCastChildren(ref location, out hit);
// If raycast failed, then find any control under mouse (hierarchical)
hit = hit ?? GetChildAtRecursive(location);
if (hit is View || hit is CanvasContainer)
hit = null;
return hit != null;
#endif
}
private UIControlNode FindUIControlNode(Control control)

View File

@@ -435,6 +435,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
case InputDevice::EventType::MouseMove:
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
break;
case InputDevice::EventType::MouseMoveRelative:
window->OnMouseMoveRelative(e.MouseMovementData.PositionRelative);
break;
case InputDevice::EventType::MouseLeave:
window->OnMouseLeave();
break;
@@ -501,7 +504,8 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
return false;
const ISerializable::DeserializeStream& newRootData = **newRootDataPtr;
Guid prefabId, prefabObjectID;
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") && JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") &&
JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
{
const auto nestedPrefab = Content::Load<Prefab>(prefabId);
if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID)
@@ -511,21 +515,6 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
return true;
}
DEFINE_INTERNAL_CALL(void) EditorInternal_GetPrefabNestedObject(Guid* prefabId, Guid* prefabObjectId, Guid* outPrefabId, Guid* outPrefabObjectId)
{
*outPrefabId = Guid::Empty;
*outPrefabObjectId = Guid::Empty;
const auto prefab = Content::Load<Prefab>(*prefabId);
if (!prefab)
return;
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(*prefabObjectId);
if (!prefabObjectDataPtr)
return;
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
JsonTools::GetGuidIfValid(*outPrefabId, prefabObjectData, "PrefabID");
JsonTools::GetGuidIfValid(*outPrefabObjectId, prefabObjectData, "PrefabObjectID");
}
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
{
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;

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
@@ -1008,7 +1013,7 @@ namespace FlaxEditor.Modules
ContentItem item;
if (path.EndsWith(".cs"))
item = new CSharpScriptItem(path);
else if (path.EndsWith(".cpp") || path.EndsWith(".h"))
else if (path.EndsWith(".cpp") || path.EndsWith(".h") || path.EndsWith(".c") || path.EndsWith(".hpp"))
item = new CppScriptItem(path);
else if (path.EndsWith(".shader") || path.EndsWith(".hlsl"))
item = new ShaderSourceItem(path);
@@ -1140,6 +1145,7 @@ namespace FlaxEditor.Modules
Proxy.Add(new CSharpEmptyStructProxy());
Proxy.Add(new CSharpEmptyInterfaceProxy());
Proxy.Add(new CSharpActorProxy());
Proxy.Add(new CSharpGamePluginProxy());
Proxy.Add(new CppAssetProxy());
Proxy.Add(new CppStaticClassProxy());
Proxy.Add(new CppScriptProxy());
@@ -1229,8 +1235,6 @@ namespace FlaxEditor.Modules
LoadProjects(Game.Project);
}
RebuildInternal();
Editor.ContentImporting.ImportFileEnd += (obj, failed) =>
{
var path = obj.ResultUrl;
@@ -1238,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)
@@ -1312,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()
{
@@ -1339,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

@@ -222,7 +222,7 @@ namespace FlaxEditor.Modules
outputExtension = extension;
// Check if can place source files here
if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h"))
if (!targetLocation.CanHaveScripts && (extension == ".cs" || extension == ".cpp" || extension == ".h" || extension == ".c" || extension == ".hpp"))
{
// Error
Editor.LogWarning(string.Format("Cannot import \'{0}\' to \'{1}\'. The target directory cannot have scripts.", inputPath, targetLocation.Node.Path));
@@ -391,6 +391,20 @@ namespace FlaxEditor.Modules
public override void OnInit()
{
ImportFileEntry.RegisterDefaultTypes();
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
}
private void OnScriptsReloadBegin()
{
// Remove import file types from scripting assemblies
List<string> removeFileTypes = new List<string>();
foreach (var pair in ImportFileEntry.FileTypes)
{
if (pair.Value.Method.IsCollectible || (pair.Value.Target != null && pair.Value.Target.GetType().IsCollectible))
removeFileTypes.Add(pair.Key);
}
foreach (var fileType in removeFileTypes)
ImportFileEntry.FileTypes.Remove(fileType);
}
/// <inheritdoc />
@@ -451,6 +465,7 @@ namespace FlaxEditor.Modules
/// <inheritdoc />
public override void OnExit()
{
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
EndWorker();
}
}

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)

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