445 Commits

Author SHA1 Message Date
d955303df7 Use the OpenAL Git repository as a source for building other platforms
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-10-14 01:01:13 +03:00
6ca949e70b Fix glslang python update script for Mac and error on failure 2025-10-13 23:22:44 +03:00
afecf984e3 Update package requirements for Wayland 2025-10-13 23:20:37 +03:00
85fad2b6bf Add support for building dependencies with specific architecture 2025-10-13 23:20:36 +03:00
aee1fd285e Fix CMake compatibility errors with dependencies 2025-10-13 23:20:36 +03:00
9b464c6530 Support Visual Studio 2026 as a generator for CMake dependencies 2025-10-13 23:20:36 +03:00
3ea807468e Update SDL to 3.2.24 2025-10-12 17:18:39 +03:00
0f135597fa Merge remote-tracking branch 'origin/master' into sdl_platform 2025-10-12 11:18:28 +03:00
Wojtek Figat
8da0d2c4ce Merge branch 'xxSeys1-IndustryStandardSettingsShortcut' 2025-10-10 08:31:40 +02:00
Wojtek Figat
20f576783b Merge branch 'IndustryStandardSettingsShortcut' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-IndustryStandardSettingsShortcut 2025-10-10 08:31:32 +02:00
Wojtek Figat
ef2c551cee Fix build 2025-10-08 23:24:15 +02:00
Wojtek Figat
65cf59642c Fix changing Rigid Body center of mass offset
#2325 #3247
2025-10-08 22:16:46 +02:00
Wojtek Figat
e2fc8a6283 Add drawing RigidBody center of mass and attached colliders
#2325 #3247
2025-10-08 22:16:16 +02:00
Wojtek Figat
73976f3ed9 Fix box collider to properly draw small bounds 2025-10-08 22:08:34 +02:00
Wojtek Figat
7ab6bafe39 Fix crash when saving empty json string 2025-10-08 22:02:05 +02:00
Wojtek Figat
deb2ad7c8f Fix font hit test on multi-line text past the line end character
#3503
2025-10-08 16:36:34 +02:00
Wojtek Figat
cd7fc3242e Merge branch 'ZaPx64-ZaPx64-texture-asset-save-fix' 2025-10-08 09:14:59 +02:00
Wojtek Figat
31a0a77e7c Merge branch 'ZaPx64-texture-asset-save-fix' of https://github.com/ZaPx64/FlaxEngine into ZaPx64-ZaPx64-texture-asset-save-fix 2025-10-08 09:14:54 +02:00
Wojtek Figat
f0ec4a901a Merge branch 'xxSeys1-StraightenConnectionFix' 2025-10-08 09:13:45 +02:00
ZaPx64
3682159da6 Fix Save() failing on virtual texture asset 2025-10-05 09:20:54 +02:00
Saas
e9f83f77bb fix "Straighten Connections" to actually straighten all connections 2025-10-04 14:03:02 +02:00
Wojtek Figat
8f3b80492e Fix terrain physics error on end play when it's disabled
#3590 #3603
2025-10-03 22:30:44 +02:00
Wojtek Figat
c61c013517 Merge branch 'xxSeys1-StrokeMyEgo' 2025-10-03 22:22:11 +02:00
Wojtek Figat
a2170ffd8a Merge branch 'StrokeMyEgo' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-StrokeMyEgo 2025-10-03 22:22:07 +02:00
Wojtek Figat
4f1f77fb32 Simplify code of EditorViewport to access editor instance 2025-10-03 22:21:11 +02:00
Wojtek Figat
6ae370f8fc Fix camera cut flag in rendering to not trigger on origin change for smother visuals 2025-10-03 22:20:58 +02:00
Saas
da5c8555e5 add myself to list of Flax authors lol
Mafi said I should do this :)
2025-10-03 21:16:28 +02:00
Saas
c4c7ee941f add industry standard shortcut for editor settings 2025-10-03 14:46:43 +02:00
Wojtek Figat
4f45b3c1d0 Fix missing root motion copy when using input skeleton pose (eg. IK node)
#3445
2025-10-03 11:33:01 +02:00
Wojtek Figat
4c640b915f Fix CheckBox to display check state when created in game without editor icon atlas
#3705
2025-10-03 11:25:25 +02:00
Wojtek Figat
1f3f1ea67e Fix Blend Poses nodes to smoothly blend back when transition goes back
#3595
2025-10-03 10:52:01 +02:00
Wojtek Figat
60c19303f6 Fix duplicating splines with parents
#3531
2025-10-02 23:31:03 +02:00
Wojtek Figat
adcfc50218 Fix stack overflow exception in shader graph recursion to be detected
#3706
2025-10-02 20:49:50 +02:00
Wojtek Figat
9b812ec34a Fix BoundingFrustum::GetPlane in C++ to match C# version (and doc comment) 2025-10-02 18:48:32 +02:00
Wojtek Figat
7e1ac5e167 Fix sky rendering in ortho and oblique projection
#3448
2025-10-02 18:48:14 +02:00
Wojtek Figat
028b5fedec Use right-click only on GPUTextureEditor context menu 2025-09-30 23:37:15 +02:00
Wojtek Figat
9cc2c1da40 Fix terrain exporting to properly calculate size and sample positions
#3534
2025-09-30 22:58:08 +02:00
Wojtek Figat
5ed8564293 Merge branch 'xxSeys1-visjectPanOnNode' 2025-09-30 16:08:37 +02:00
Wojtek Figat
7c87ade12b Merge branch 'visjectPanOnNode' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-visjectPanOnNode 2025-09-30 15:51:17 +02:00
Wojtek Figat
7f87678282 Merge branch 'xxSeys1-IssueTemplateFix' 2025-09-30 15:49:18 +02:00
Wojtek Figat
e429d29d17 Merge branch 'IssueTemplateFix' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-IssueTemplateFix 2025-09-30 15:49:11 +02:00
Wojtek Figat
537d8b57ca Revert "Merge branch 'NoClearSearchboxesWhenStuffHappens' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-NoClearSearchboxesWhenStuffHappens"
This reverts commit 1186833b2d, reversing
changes made to bb180b0f59.

#3687 #3701
2025-09-26 22:25:49 +02:00
Saas
4a3fb41035 further fixes and make some stuff a bit nicer 2025-09-25 13:32:21 +02:00
Saas
797cb3c3f2 fix 1.10 becoming 1.1 and some spelling issue in issue template 2025-09-23 20:56:43 +02:00
Wojtek Figat
47670251ef Merge branch 'Tryibion-issue-template' 2025-09-23 17:21:34 +02:00
Wojtek Figat
cf1ef91246 Merge branch 'issue-template' of https://github.com/Tryibion/FlaxEngine into Tryibion-issue-template 2025-09-23 17:21:30 +02:00
Wojtek Figat
7060cb5696 Fix UI Brush editing in prefab regression from a471861e92
#3694
2025-09-23 17:20:18 +02:00
Wojtek Figat
c449833d35 Merge branch 'Tryibion-audio-events' 2025-09-23 17:07:22 +02:00
Wojtek Figat
284aeca51a Merge branch 'audio-events' of https://github.com/Tryibion/FlaxEngine into Tryibion-audio-events 2025-09-23 17:07:18 +02:00
Wojtek Figat
d8f7199c11 Fix importing emissive, roughness, metalness and wireframe properties of materials with Assimp
#3418
2025-09-23 15:42:49 +02:00
Wojtek Figat
dc05bbbbcd Merge branch 'IceReaper-feature/create_project' 2025-09-22 22:45:50 +02:00
Wojtek Figat
3fcc9ed01f Merge branch 'feature/create_project' of https://github.com/IceReaper/FlaxEngine into IceReaper-feature/create_project 2025-09-22 22:32:43 +02:00
Wojtek Figat
70ba750a5e Fix code #3511 2025-09-22 22:31:23 +02:00
Wojtek Figat
50271199ac Merge branch 'xxSeys1-moveVisjectConnection' 2025-09-22 22:30:32 +02:00
Wojtek Figat
d1a99c9396 Merge branch 'moveVisjectConnection' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-moveVisjectConnection
# Conflicts:
#	Source/Editor/Surface/VisjectSurface.cs
2025-09-22 22:30:26 +02:00
Chandler Cox
4ae3d57adc Resolve code suggestions 2025-09-22 11:32:24 -05:00
Wojtek Figat
99b9967806 Merge branch 'xxSeys1-ViewportIconsMoreCustomization' 2025-09-22 18:10:38 +02:00
Wojtek Figat
2f7e84253a Merge branch 'ViewportIconsMoreCustomization' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-ViewportIconsMoreCustomization 2025-09-22 18:10:33 +02:00
Wojtek Figat
2f55cb938f Merge branch 'xxSeys1-commandSuggestionImprovements' 2025-09-22 18:08:30 +02:00
Wojtek Figat
a86661a855 Merge branch 'commandSuggestionImprovements' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-commandSuggestionImprovements 2025-09-22 18:06:55 +02:00
Wojtek Figat
a68ce6633a Merge branch 'Tryibion-vs-code-plugin-organize' 2025-09-22 18:02:52 +02:00
Wojtek Figat
5d57afe3aa Merge branch 'vs-code-plugin-organize' of https://github.com/Tryibion/FlaxEngine into Tryibion-vs-code-plugin-organize 2025-09-22 18:02:00 +02:00
Wojtek Figat
6705138247 Merge branch 'xxSeys1-SmallVehicleImprovements' 2025-09-22 16:18:17 +02:00
Wojtek Figat
276caf771c Merge branch 'SmallVehicleImprovements' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-SmallVehicleImprovements
# Conflicts:
#	Source/Engine/Physics/Actors/WheeledVehicle.h
2025-09-22 16:18:12 +02:00
Wojtek Figat
5eea5a72c9 Fix particle material compilation error when using position offset
#3661
2025-09-22 11:44:11 +02:00
Wojtek Figat
e9a7b1c8eb Fix using enums as Scene Animation Event parameters
#3554
2025-09-22 10:22:32 +02:00
Wojtek Figat
a151c78412 Fix loading projects that have similar path to engine folder
#3565
2025-09-22 08:42:16 +02:00
Wojtek Figat
5f1e905e8f Fix crash when importing model as prefab and handle duplicated object names
#3558
2025-09-21 22:52:57 +02:00
Wojtek Figat
a0f764a774 Add skybox rotation feature
#3592
2025-09-21 21:58:03 +02:00
Wojtek Figat
7da5ce3ed4 Merge branch 'xxSeys1-NoClearSearchboxesWhenStuffHappens' 2025-09-21 21:06:21 +02:00
Wojtek Figat
1186833b2d Merge branch 'NoClearSearchboxesWhenStuffHappens' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-NoClearSearchboxesWhenStuffHappens 2025-09-21 21:06:16 +02:00
Wojtek Figat
bb180b0f59 Merge branch 'Tryibion-fix-physics-attach-rigid' 2025-09-21 21:04:59 +02:00
Wojtek Figat
5d1c79929a Merge branch 'fix-physics-attach-rigid' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-physics-attach-rigid 2025-09-21 21:04:56 +02:00
Wojtek Figat
3f5a4cc4c9 Merge branch 'Tryibion-fix-dup&remove' 2025-09-21 21:02:22 +02:00
Wojtek Figat
62fd8ac967 Merge branch 'fix-dup&remove' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-dup&remove 2025-09-21 21:02:17 +02:00
Wojtek Figat
d904b92f2e Merge branch 'xxSeys1-LessCreateScriptItems' 2025-09-21 21:01:36 +02:00
Wojtek Figat
87e2b76ffa Merge branch 'LessCreateScriptItems' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-LessCreateScriptItems 2025-09-21 21:01:33 +02:00
Wojtek Figat
c5e11aed15 Merge branch 'xxSeys1-WidgetCreateFilterControlTypes' 2025-09-21 21:00:27 +02:00
Wojtek Figat
85d61b334b Merge branch 'WidgetCreateFilterControlTypes' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-WidgetCreateFilterControlTypes 2025-09-21 21:00:11 +02:00
Wojtek Figat
26e94f6f8e Refactor material instance to not override all public parameters by default (need explicit set)
#3444
2025-09-21 20:59:25 +02:00
Wojtek Figat
902744a0ce Fix model import scale on nodes that could be applied multiple times on the same mesh
#3562
2025-09-21 15:08:35 +02:00
Wojtek Figat
1c581bceaf Fix sun shadows when direction is perfectly vertical
#3614
2025-09-20 23:52:04 +02:00
Wojtek Figat
9cc44825c6 Update engine materials 92f4327fc2 2025-09-20 00:14:51 +02:00
Wojtek Figat
92f4327fc2 Fix missing volumetric fog affecting transparent materials
#3436
2025-09-20 00:13:52 +02:00
Wojtek Figat
47711ec5be Fix Volumetric Fog flicker on camera cuts
#3443
2025-09-19 23:10:03 +02:00
Chandler Cox
d1fbc66cb9 Fix not attaching updated collision data to rigid body. 2025-09-19 15:58:22 -05:00
Saas
7183a3306e fix typo 2025-09-19 16:57:50 +02:00
Saas
fd191f7ffb don't clear content panel folder- and scene tree search box on script reload and enter/ exit play 2025-09-18 23:24:10 +02:00
Saas
2604d58687 no more Linq 2025-09-18 17:37:04 +02:00
Chandler Cox
01d1d634c2 Fix other missing duplicate. 2025-09-16 17:43:55 -05:00
Chandler Cox
c7e403661d Dont allow remove and duplicate options for non-resizing collections. 2025-09-16 17:42:24 -05:00
Saas
1196db6d17 check if control is control meant for gui editor use 2025-09-16 22:54:57 +02:00
Saas
553a007508 Revert "hide TrackLabel control in editor"
This reverts commit 364a523375.
2025-09-16 22:14:22 +02:00
Saas
de2ee36529 fix naming lol 2025-09-16 22:07:42 +02:00
Saas
eea44ac897 remove search query highlights showing on create new script item 2025-09-16 22:06:49 +02:00
Saas
c124713e99 remove create new script items when searchbox is cleared 2025-09-16 22:05:28 +02:00
Saas
364a523375 hide TrackLabel control in editor 2025-09-16 22:04:24 +02:00
Wojtek Figat
afdd264e63 Fix compilation of Editor in Release mode 2025-09-16 16:34:58 +02:00
Wojtek Figat
8ec54f7b1c Merge branch 'cNori-Custom-editor-for-GPUTextures' 2025-09-16 00:16:10 +02:00
Wojtek Figat
521518bde4 Add hack to use GPUTextureEditor on ref pickers 2025-09-16 00:15:58 +02:00
Wojtek Figat
56077a268a SImplify and cleanup GPUTexture editor #3452 #3194 2025-09-16 00:15:48 +02:00
Wojtek Figat
a0ca000793 Merge branch 'Custom-editor-for-GPUTextures' of https://github.com/cNori/FlaxEngineFork into cNori-Custom-editor-for-GPUTextures 2025-09-15 18:08:02 +02:00
Wojtek Figat
ae4ae7a638 Fix rich textbox vertical alignment
#3502
2025-09-15 15:17:18 +02:00
Wojtek Figat
e2a4c8ab03 Merge branch 'Tryibion-fix-viewdistance-light' 2025-09-15 14:14:04 +02:00
Chandler Cox
7a40722964 Fix view distance light property from affecting brightness all of the time. 2025-09-14 17:51:27 -05:00
Wojtek Figat
1de8909d05 Merge branch 'Tryibion-prefab-viewport-scaling' 2025-09-14 23:59:45 +02:00
Wojtek Figat
9749487e24 Move prefab and game UI size context menu to shared UI Module
#3571
2025-09-14 23:59:40 +02:00
Wojtek Figat
55968a8ddc Merge branch 'prefab-viewport-scaling' of https://github.com/Tryibion/FlaxEngine into Tryibion-prefab-viewport-scaling 2025-09-14 23:11:59 +02:00
Wojtek Figat
e325b190ea Merge branch 'xxSeys1-disabledGizmoBrightness' 2025-09-14 22:01:18 +02:00
Wojtek Figat
ada6b9140f Minor adjustments for #3411 2025-09-14 22:00:57 +02:00
Wojtek Figat
5582579173 Merge branch 'disabledGizmoBrightness' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-disabledGizmoBrightness 2025-09-14 21:45:57 +02:00
Wojtek Figat
88773e71e5 Fix warning when cloning actor from prefab that is not a root
#3578
2025-09-14 14:25:19 +02:00
Wojtek Figat
9e1f488f22 Fix prefab window to use UI Mode for empty UI Control prefab
#3574
2025-09-13 14:41:11 +02:00
Wojtek Figat
a471861e92 Fix editing UI Brush in prefabs
#3501
2025-09-12 23:15:13 +02:00
Wojtek Figat
3d182c89f3 Add MaterialShader::BindParameters to usable in game scripts
#3668
2025-09-12 18:04:01 +02:00
Wojtek Figat
e3810a9938 Merge branch 'GoaLitiuM-vs2026' 2025-09-12 18:02:07 +02:00
f0dea9d528 Add support for Visual Studio 2026 and v145 MSVC toolset 2025-09-10 20:05:56 +03:00
d70a003617 Improve tab-less dock window behavior in other platforms
Add checks for #3215 to hide the tab bar only if it doesn't prevent
window dragging in Wayland sessions with native decorations.
2025-09-07 19:27:24 +03:00
b443b74d18 Merge branch 'master' into sdl_platform
# Conflicts:
#	Source/Editor/GUI/Docking/DockHintWindow.cs
#	Source/Editor/Options/InterfaceOptions.cs
2025-09-07 19:02:09 +03:00
Wojtek Figat
eff5f84185 Improve shadow maps sharing in nested scene rendering 2025-09-02 22:14:07 +02:00
Wojtek Figat
ad1163bccc Fix HashSet::Add returning incorrect value 2025-09-02 21:41:54 +02:00
Wojtek Figat
1042ad4e7d Fix object ids remapping inside nested prefabs
#3255
2025-09-02 21:41:36 +02:00
Wojtek Figat
8fdda1a71a Fix scene object reference serialization in C++ to use correct serializer
#3255
2025-08-30 23:52:54 +02:00
Wojtek Figat
3f7fe635d8 Fix 5222f1d35c for inactive preprocessor conditional block 2025-08-29 23:04:46 +02:00
Wojtek Figat
fcebc57ed0 Merge branch 'xxSeys1-addSphere' 2025-08-29 22:32:21 +02:00
Wojtek Figat
c40e447bb7 Merge branch 'addSphere' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-addSphere 2025-08-29 22:31:00 +02:00
Wojtek Figat
e6f94bb154 Merge branch 'fibref-textrender-scaling-fix' 2025-08-29 22:27:41 +02:00
Wojtek Figat
adbc546978 Merge branch 'textrender-scaling-fix' of https://github.com/fibref/FlaxEngine into fibref-textrender-scaling-fix 2025-08-29 22:26:32 +02:00
Wojtek Figat
2d171967e9 Merge branch 'Tryibion-collection-duplicate' 2025-08-29 22:24:58 +02:00
Wojtek Figat
33a0e6ac7d Merge branch 'collection-duplicate' of https://github.com/Tryibion/FlaxEngine into Tryibion-collection-duplicate 2025-08-29 22:24:09 +02:00
Wojtek Figat
848cc38bf1 Fix reverting prefab object reference in nested prefabs
#3255
2025-08-29 22:04:03 +02:00
Wojtek Figat
91cd1e8065 Fix regression from ef7c7f2d30 to ignore unmodified scripts in diff 2025-08-29 21:49:14 +02:00
Wojtek Figat
9fafb47abb Fix debug drawing wheeled vehicle in prefab viewport
#3591
2025-08-29 21:03:44 +02:00
Wojtek Figat
5222f1d35c Add support for parsing inheritance with preprocessor blocks inside it 2025-08-29 21:03:04 +02:00
Wojtek Figat
785649f9d5 Merge branch 'Tryibion-show-prefab-add-delete' 2025-08-28 23:48:33 +02:00
Wojtek Figat
d47ac95681 Modernize the code to use unified scene access #3513 2025-08-28 23:48:25 +02:00
Wojtek Figat
703e0cb7ca Merge branch 'show-prefab-add-delete' of https://github.com/Tryibion/FlaxEngine into Tryibion-show-prefab-add-delete 2025-08-28 22:56:22 +02:00
Wojtek Figat
ef7c7f2d30 Fix script fields prefab diff showing and reverting with undo
#3594
2025-08-28 22:52:46 +02:00
Wojtek Figat
f3d375e356 Fix prefab root name and transform being changed when applying local changes of sub-object
#3235
2025-08-28 22:26:50 +02:00
frank
a3073321cf fix scaling for TextRender 2025-08-28 17:24:06 +08:00
Chandler Cox
824b49dd88 Better duplication of collection. 2025-08-26 20:25:02 -05:00
Wojtek Figat
d0e7bff03a Merge branch 'Tryibion-add-collision-v&t' 2025-08-26 18:05:46 +02:00
Wojtek Figat
d314d5b324 Format memory usage to human-readable format
#3495
2025-08-26 18:05:42 +02:00
Wojtek Figat
a027ed3b63 Merge branch 'add-collision-v&t' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-collision-v&t 2025-08-26 17:57:01 +02:00
Wojtek Figat
bcedb05a2c Fix regression from 6a8553a277 on local lights 2025-08-26 17:55:32 +02:00
Wojtek Figat
b36be95947 Fix Editor undo on collection properties that return different object on get
#3256
2025-08-26 14:59:10 +02:00
Wojtek Figat
4ca399af71 Add model import options auto-restore from model prefab 2025-08-25 23:15:37 +02:00
Wojtek Figat
c1f022520d Update ReSharper settings 2025-08-25 22:15:44 +02:00
Wojtek Figat
2efd20f223 Merge branch 'xxSeys1-ToolboxSearchFilterAndControls' 2025-08-25 22:15:08 +02:00
Wojtek Figat
00dd432fbc Simplify code #3360 2025-08-25 22:15:00 +02:00
Wojtek Figat
f707508d70 Merge branch 'ToolboxSearchFilterAndControls' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-ToolboxSearchFilterAndControls 2025-08-25 14:49:00 +02:00
Wojtek Figat
b965ca6c8c Fix Content Window navigation bar to expand toolstrip for proper scroll bar display
#3326
2025-08-25 14:38:55 +02:00
Wojtek Figat
6fea9eefaa Merge branch 'xxSeys1-BrokenLink' 2025-08-24 21:11:39 +02:00
Wojtek Figat
47caa6af28 Add BrokenLink32/BrokenLink64 icons
#3218
2025-08-24 21:11:32 +02:00
Wojtek Figat
9aedb37ac2 Merge branch 'BrokenLink' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-BrokenLink 2025-08-24 21:10:26 +02:00
Wojtek Figat
e4bc2c69c7 Merge branch 'Zode-customeditorwindow-expose-constructor' 2025-08-24 14:00:20 +02:00
Wojtek Figat
6db9265112 Merge branch 'customeditorwindow-expose-constructor' of https://github.com/Zode/FlaxEngine into Zode-customeditorwindow-expose-constructor 2025-08-24 14:00:13 +02:00
Wojtek Figat
21a84c5b84 Merge branch 'xxSeys1-AutoSizePropertiesSplitter' 2025-08-24 13:59:20 +02:00
Wojtek Figat
633b5857c9 Merge branch 'AutoSizePropertiesSplitter' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-AutoSizePropertiesSplitter 2025-08-24 13:59:16 +02:00
Wojtek Figat
9f9dac1543 Merge branch 'Tryibion-layer-methods' 2025-08-24 13:46:56 +02:00
Wojtek Figat
df6f8fd8ae Codestyle adjustments #3343 2025-08-24 13:46:53 +02:00
Wojtek Figat
4bd8ce37ac Merge branch 'layer-methods' of https://github.com/Tryibion/FlaxEngine into Tryibion-layer-methods 2025-08-24 13:43:35 +02:00
Wojtek Figat
40e204839f Merge branch 'Tryibion-splash-image' 2025-08-24 13:37:55 +02:00
Wojtek Figat
d6c75b3f86 Simplify code in #3119 2025-08-24 13:37:48 +02:00
Wojtek Figat
687c283533 Merge branch 'splash-image' of https://github.com/Tryibion/FlaxEngine into Tryibion-splash-image 2025-08-24 13:24:35 +02:00
Wojtek Figat
70ee8501a5 Merge branch 'xxSeys1-TabHeight' 2025-08-24 13:21:15 +02:00
Wojtek Figat
2c34bd2308 Merge branch 'TabHeight' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-TabHeight 2025-08-24 13:21:12 +02:00
fc341a86e7 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-08-24 09:44:28 +03:00
Wojtek Figat
5023e3277b Merge branch 'Swiggies-animated-model-additions' 2025-08-22 23:04:00 +02:00
Wojtek Figat
9003d855b3 Merge branch 'animated-model-additions' of https://github.com/Swiggies/FlaxEngine into Swiggies-animated-model-additions 2025-08-22 23:03:54 +02:00
Wojtek Figat
75906719d4 Merge branch 'xxSeys1-SimplifyListCtrlScrolling' 2025-08-22 22:34:09 +02:00
Wojtek Figat
9a59925a36 Merge branch 'SimplifyListCtrlScrolling' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-SimplifyListCtrlScrolling 2025-08-22 22:34:05 +02:00
Wojtek Figat
d5ca80c2c1 Merge branch 'Tryibion-fix-particle-effect-params-overide-update' 2025-08-22 22:31:12 +02:00
Wojtek Figat
cb07ee77aa Change #3588 to be editor-only 2025-08-22 22:31:08 +02:00
Wojtek Figat
680783f2b0 Merge branch 'fix-particle-effect-params-overide-update' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-particle-effect-params-overide-update 2025-08-22 22:29:59 +02:00
Zode
4a28b4bd6c Expose hideOnClose and scrollBars in constructor for CustomEditorWindows. 2025-08-22 01:26:34 +03:00
Wojtek Figat
4bf36f3467 Merge branch 'Tryibion-shift-select-nodes' 2025-08-19 23:00:43 +02:00
Wojtek Figat
2c1713d300 Fix rare issues with shift tree selection 2025-08-19 23:00:29 +02:00
Wojtek Figat
8136691914 Merge branch 'shift-select-nodes' of https://github.com/Tryibion/FlaxEngine into Tryibion-shift-select-nodes
# Conflicts:
#	Source/Editor/GUI/Tree/Tree.cs
2025-08-19 18:45:33 +02:00
Wojtek Figat
da23e287c0 Merge branch 'Tryibion-cookandrun-buildconfig' 2025-08-19 18:22:49 +02:00
Wojtek Figat
e0825d870d Merge branch 'cookandrun-buildconfig' of https://github.com/Tryibion/FlaxEngine into Tryibion-cookandrun-buildconfig 2025-08-19 18:22:44 +02:00
Wojtek Figat
86dbe6b93d Merge branch 'Tryibion-add-gamewin-audio-events' 2025-08-19 18:21:42 +02:00
Wojtek Figat
e71b74c625 Merge branch 'add-gamewin-audio-events' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-gamewin-audio-events 2025-08-19 18:21:32 +02:00
Wojtek Figat
45f6ef29e9 Merge branch 'xxSeys1-MoreSearchableCM' 2025-08-19 18:20:04 +02:00
Wojtek Figat
0fabca19cd Merge branch 'MoreSearchableCM' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-MoreSearchableCM 2025-08-19 18:20:01 +02:00
Wojtek Figat
0bc242c738 Merge branch 'MrCapy0-Color-Gradient-Node' 2025-08-19 13:22:34 +02:00
Wojtek Figat
8c548ceff2 Merge branch 'Color-Gradient-Node' of https://github.com/MrCapy0/FlaxEngine into MrCapy0-Color-Gradient-Node 2025-08-19 13:21:32 +02:00
Wojtek Figat
46fda05000 Merge branch 'xxSeys1-VjStraightenConnections' 2025-08-19 13:20:44 +02:00
Wojtek Figat
1fee95be1c Merge branch 'VjStraightenConnections' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-VjStraightenConnections 2025-08-19 13:20:41 +02:00
Wojtek Figat
8c66ae99a3 Merge branch 'Tryibion-initial-nuget' 2025-08-19 13:18:54 +02:00
Wojtek Figat
1cf98e2188 Merge branch 'initial-nuget' of https://github.com/Tryibion/FlaxEngine into Tryibion-initial-nuget 2025-08-19 13:18:51 +02:00
Wojtek Figat
6a8553a277 Fix incorrect Lambert Diffuse shadowing to use just N dot L for accurate lighting
#3615 #3616
2025-08-18 11:03:50 +02:00
Chandler Cox
a02b7d4a1a Add events for when audio settings are changed for the game window. 2025-08-17 11:58:42 -05:00
Wojtek Figat
606dfa4e2e Merge branch 'Tryibion-add-ctor-matbrush-inst' 2025-08-15 14:41:08 +02:00
Wojtek Figat
b6f853a01c Merge branch 'add-ctor-matbrush-inst' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-ctor-matbrush-inst 2025-08-15 14:41:05 +02:00
Wojtek Figat
fc2112ec93 Fix SSAO artifacts with "flat normals" look
#3617
2025-08-15 14:34:02 +02:00
Wojtek Figat
6ccfbfeff1 Fix saving skinned models with blend shapes
#3612
2025-08-15 14:20:16 +02:00
Wojtek Figat
f21accd466 Fix crash when memory stream reading fails and perform soft error handling
#3612
2025-08-15 14:19:59 +02:00
Chandler Cox
38b4ace1a8 Use material base as ctor parameter. 2025-08-15 07:01:48 -05:00
Wojtek Figat
774b6bd72c Update engine materials 2025-08-15 13:09:05 +02:00
Wojtek Figat
9c4606fefc Merge branch 'GoaLitiuM-linux_hotreload_cleanup_fix' 2025-08-14 22:47:05 +02:00
Wojtek Figat
0e50e47cce Merge branch 'linux_hotreload_cleanup_fix' of https://github.com/GoaLitiuM/FlaxEngine into GoaLitiuM-linux_hotreload_cleanup_fix 2025-08-14 22:46:45 +02:00
Wojtek Figat
285fa870d0 Merge branch 'Tryibion-fix-anim-event-backwards' 2025-08-14 22:41:24 +02:00
Wojtek Figat
69ed0bf56f Merge branch 'fix-anim-event-backwards' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-anim-event-backwards 2025-08-14 22:41:20 +02:00
Wojtek Figat
237b9bccd5 Merge branch 'xxSeys1-PauseOnErrorInfo' 2025-08-14 22:23:39 +02:00
Wojtek Figat
f5fd7319e1 Merge branch 'PauseOnErrorInfo' of https://github.com/xxSeys1/FlaxEngine into xxSeys1-PauseOnErrorInfo
# Conflicts:
#	Source/Editor/Windows/DebugLogWindow.cs
2025-08-14 22:23:32 +02:00
Wojtek Figat
e04c0c4ace Merge branch 'Tryibion-fix-not-finised-tag-richtextbox' 2025-08-14 22:21:31 +02:00
Wojtek Figat
f6d0b073da Merge branch 'fix-not-finised-tag-richtextbox' of https://github.com/Tryibion/FlaxEngine into Tryibion-fix-not-finised-tag-richtextbox 2025-08-14 22:21:27 +02:00
Wojtek Figat
68a7cf4f18 Merge branch 'Tryibion-make-empty-stringview-const' 2025-08-14 22:15:58 +02:00
Wojtek Figat
a91360529f Merge branch 'make-empty-stringview-const' of https://github.com/Tryibion/FlaxEngine into Tryibion-make-empty-stringview-const 2025-08-14 22:15:53 +02:00
Wojtek Figat
bf9ca14deb Fix sampling textures in decals to use custom mip-level
#3599
2025-08-14 22:14:03 +02:00
Wojtek Figat
cb92a2b8cb Optimize decals rendering with depth test
#3599
2025-08-14 13:04:57 +02:00
Wojtek Figat
8a73d79936 Update engine materials 2025-08-14 12:24:12 +02:00
Wojtek Figat
2f7d7a0f2a Allow pasting State nodes in Anim Graph
#3596
2025-08-14 12:24:02 +02:00
Wojtek Figat
d43c0c593f Merge branch 'Tryibion-add-scaled-time-node' 2025-08-14 11:54:34 +02:00
Wojtek Figat
1087bd2445 Fix #3342 to properly place new param in Constant Buffer
#3299
2025-08-14 11:53:25 +02:00
Wojtek Figat
5e19a9729b Merge branch 'add-scaled-time-node' of https://github.com/Tryibion/FlaxEngine into Tryibion-add-scaled-time-node 2025-08-14 11:37:09 +02:00
Wojtek Figat
69e12d77be Add preventing autosave when using editor context menus
#3220
2025-08-13 23:25:57 +02:00
Saas
169d3e964d Switch from Debug.Write to Editor.Log 2025-08-13 13:29:13 +02:00
Chandler Cox
cf503cf921 Add material instance ctor for MaterialBrush 2025-08-12 21:03:35 -05:00
Wojtek Figat
6fd4ef735e Add InvokeOnUpdate to C++ scripting api 2025-08-12 23:35:12 +02:00
Wojtek Figat
303087c4c4 Fix regression in renaming textbox placement of newly added actor to prefab 2025-08-12 23:18:18 +02:00
68da28ffe8 Update SDL to 3.2.20 2025-08-12 15:39:19 +03:00
Wojtek Figat
427e76e76e Update volk to version 1.4.304 2025-08-12 15:24:48 +03:00
b183b5bcfc Merge remote-tracking branch 'origin/master' into sdl_platform 2025-08-12 15:22:34 +03:00
Chandler Cox
e27880c1e6 Make plugins into their own folders in VSCode. Order VSCode plugin folders with Engine at the bottom. 2025-08-02 09:28:49 -05:00
Chandler Cox
6f15ef7690 Fix location of clip start call. 2025-08-01 15:15:54 -05:00
Chandler Cox
0e3a22faa0 Fix spelling in comment. 2025-08-01 15:11:06 -05:00
Chandler Cox
0dc1e04c89 Add slider to audio debug editor for selecting time. 2025-08-01 15:07:49 -05:00
Chandler Cox
5c7712daad Add audio clip started and finished events to audio source 2025-08-01 15:07:25 -05:00
Wojtek Figat
f37b75df7b Add support for using shadow maps from linked scene rendering (eg. for 1p weapons) 2025-07-25 19:59:58 +02:00
Wojtek Figat
6132e45e25 Fix shadow lights checking loop if shadows are disabled 2025-07-25 16:00:44 +02:00
Chandler Cox
753035c452 Fix issue with infinite loop if \ is used instead of / for tag closing. 2025-07-24 18:04:39 -05:00
Chandler Cox
2dc44ac1a6 Fix infinite loop on rich text box tag parsing with incomplete end of tag. 2025-07-23 19:52:42 -05:00
Chandler Cox
d6a33d5a1c Add const to String::Empty 2025-07-23 10:23:30 -05:00
Chandler Cox
6cbd40e6d8 Make StringView::Empty const to fix issues with user accidentally changing the value. 2025-07-22 22:01:55 -05:00
Chandler Cox
b8e00f2ed1 Change checking max to use ceiltoint 2025-07-19 21:30:49 -05:00
Chandler Cox
b6e18ccae5 Fix edge case for anim event on min or max frame when looping. Fix anim event playback when is running negative. 2025-07-19 21:05:57 -05:00
Chandler Cox
1fb6586dff Add collection item duplication. 2025-07-19 16:09:33 -05:00
Chandler Cox
e6265105b5 Move to interface options. 2025-07-19 15:39:11 -05:00
Olly Rybak
f8dadac453 Fixed up some names and added docs 2025-07-19 22:37:35 +10:00
Chandler Cox
fc46219a82 Add support for multi-select disable. 2025-07-17 23:09:36 -05:00
Chandler Cox
2546e19d65 Add shift selection for tree nodes 2025-07-17 23:07:06 -05:00
Wojtek Figat
bb37f980ed Fix regression in debug draw from 4af26a5516 2025-07-14 20:25:49 +02:00
Wojtek Figat
10e9aee8ce Add particle data layout debugger tab 2025-07-14 10:28:43 +02:00
Wojtek Figat
4af26a5516 SImplify editor code for actors debug shapes drawing 2025-07-11 23:00:53 +02:00
Wojtek Figat
3e82e550f3 Add option for debug shapes drawing for particle emitters
#3267
2025-07-11 23:00:41 +02:00
Saas
33b540ed9e fix naming and treat unfolded category items as normal items 2025-07-10 20:07:52 +02:00
Saas
50871d8885 simplify and fix edge case in item list scrolling while holding control 2025-07-09 18:41:41 +02:00
xxSeys1
83374164db haha I did not copy paste that comment 2025-07-06 21:31:26 +02:00
xxSeys1
c5bfc6bc3d add option to add sphere in add colliders menu 2025-07-06 21:28:01 +02:00
Chandler Cox
d698bf96cc Apply particle effect parameter overrides when emitter is changed and when activated in the tree. 2025-07-05 19:36:45 -05:00
Chandler Cox
b3f88e156c Small change to out variable that is not used anymore. 2025-07-05 18:11:26 -05:00
Chandler Cox
7418d60f24 Add editor option for build configuration when using cook and run. 2025-07-05 18:09:30 -05:00
MrCapy0
3981d5090c change color gradiant node 8 to 11 stops 2025-07-05 10:27:45 -04:00
51feaa0730 Release mouse relative mode when focus changes during mouse tracking
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-07-03 23:21:42 +03:00
8e69aa8bd6 Fix error while closing Editor
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-07-03 22:57:07 +03:00
90b2fded48 Merge remote-tracking branch 'origin/master' into sdl_platform
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
# Conflicts:
#	Source/Editor/Windows/SceneTreeWindow.cs
2025-07-03 22:05:29 +03:00
9125ffeb9e Update third-party label in About dialog 2025-07-03 22:02:37 +03:00
28980e5fbf Cleanup 2025-07-03 22:02:36 +03:00
aab0d772a4 Implement client-side window decorations for Editor windows 2025-07-03 22:02:36 +03:00
a93a940630 Fix hot-reload files not getting cleaned up during startup
Implements minimal required filter support for `FileSystem::DirectoryGetFiles`
in order to support removing hot-reload files on Linux/Apple systems.
2025-07-03 19:41:43 +03:00
3e353db1fa Refactor UnixFileSystem 2025-07-03 19:41:43 +03:00
xxSeys1
75647d149a make visual script editor method override cm searchable 2025-06-28 19:40:03 +02:00
Chandler Cox
52b64540ab Add extra index guard logic 2025-06-28 10:46:11 -05:00
xxSeys1
d7ab497b0e fix adding empty multi action to undo stack 2025-06-28 16:22:29 +02:00
xxSeys1
683a48a6e3 add default shortcuts to distribute node options 2025-06-28 16:02:44 +02:00
xxSeys1
a41fc51f92 add visject node formatting option to straighten node connections
Also fixes a bunch of missing trailing "." in doc comments and changes "Node editors" category in the input options to "Node Editors" to match the case of all other categories.
2025-06-28 15:53:32 +02:00
Chandler Cox
b9cfd054c1 Remove unused variable 2025-06-27 21:38:10 -05:00
Chandler Cox
53d4ea51af Add prefab UI viewport scaling. 2025-06-27 21:18:53 -05:00
6296e1a9eb Fix linker errors 2025-06-26 15:32:38 +03:00
1586bb0702 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-26 15:31:59 +03:00
edeaf6af09 Fix compilation without SDL 2025-06-24 22:57:49 +03:00
951edd95db Cleanup 2025-06-24 16:47:45 +03:00
9951211596 Fix mono glib.h wrapper compilation error 2025-06-24 16:47:20 +03:00
6d337464f7 Support XDG Desktop Portal as color picker provider
Wayland and XWayland fallback implementation uses XDP in
order to query picked color from desktop.
2025-06-24 16:41:32 +03:00
d0b552d74a Use logo as an icon in Linux windows 2025-06-23 18:58:02 +03:00
83512822b1 Support clipboard actions in Content Browser and Scene tree on Wayland
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-06-23 17:50:02 +03:00
ccb78103ec Support clipboard actions in Content Browser and Scene tree on X11 2025-06-23 17:07:10 +03:00
6e79ffea34 Fix clipboard not working on X11 2025-06-23 17:07:10 +03:00
4f03d37a17 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-23 12:03:41 +03:00
Chandler Cox
c8622d1801 Change method name from add to restore. 2025-06-20 15:26:58 -05:00
Chandler Cox
fdd22c3380 Remove extra code. 2025-06-19 22:09:33 -05:00
Chandler Cox
53761df85e Add utility methods for redundant code. 2025-06-19 22:07:28 -05:00
Chandler Cox
ecaae2b458 Add downloading nuget package if needed. 2025-06-19 21:34:55 -05:00
6fb8419b3c Disable window flashing on Wayland to fix focus issues 2025-06-17 14:23:20 +03:00
a4272d6ca9 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-17 14:19:46 +03:00
4654117d5e Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-16 17:09:22 +03:00
6ff260d052 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-16 14:09:29 +03:00
88d2b72822 Update SDL to 3.3.x
Fixes popup focus issues on Linux
2025-06-16 14:09:04 +03:00
xxSeys1
a4d3ede368 fix context menu on reroute node 2025-06-15 02:08:47 +02:00
xxSeys1
92edb996f2 properly handle connecting to a box that already has a connection 2025-06-14 17:20:28 +02:00
xxSeys1
2e0c35e6e4 fix out of range error when searching visject cm 2025-06-14 01:04:35 +02:00
xxSeys1
baba151d8a fix context menu 2025-06-14 00:54:16 +02:00
xxSeys1
b44d4107c0 fixes 2025-06-13 22:25:02 +02:00
xxSeys1
f40c67ddf0 add support to move visject socket connections 2025-06-13 22:05:57 +02:00
xxSeys1
ec154b4998 remove unnecessary returns xml doc comment 2025-06-12 19:31:32 +02:00
Chandler Cox
28eaac37dc Initial work on nuget packages. 2025-06-11 18:17:19 -05:00
xxSeys1
6997cbeb47 add options for viewport icons 2025-06-11 13:08:59 +02:00
29868531ad SDL workaround for window size and position not updating
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-06-08 18:57:57 +03:00
95dfb6fdc6 Reduce minimum default window size for CommandLineBox popup 2025-06-08 18:57:12 +03:00
8df3999f85 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-04 19:30:30 +03:00
Chandler Cox
6b78b498f7 Use direct count from internal call. 2025-06-04 10:17:41 -05:00
xxSeys1
c4130aa20f fix and improve show all commands on " " behavior 2025-06-04 15:23:42 +02:00
Chandler Cox
71991ff8c7 Show added and removed actors in prefab diff view. 2025-06-03 15:25:45 -05:00
xxSeys1
c9fe9213b3 add showing all commands if prompt is whitespace(s) 2025-06-02 23:25:50 +02:00
xxSeys1
608839b6a5 set width of command suggestions based on longest command 2025-06-02 22:33:22 +02:00
149b189629 Update SDL to 3.2.16 2025-06-02 19:23:34 +03:00
b1fd86e6b5 Merge remote-tracking branch 'origin/master' into sdl_platform 2025-06-02 18:15:16 +03:00
5e8fdf879d Fix logging in gamepad related events 2025-06-02 18:15:10 +03:00
Chandler Cox
954cf3eb5b Add option to show verticies and triangles of collision model in a collider data window. 2025-05-23 17:57:14 -05:00
Olly Rybak
245d7de818 Fixed renamed parameters 2025-05-14 19:45:29 +10:00
Olly
49e0cc937e Added SetNodeTransformation with ModelBoneNode
To get and set a series of bones based on their ID

(cherry picked from commit e0a113483e910660e45c53e059502733ce1d6ad6)
2025-05-14 19:29:39 +10:00
Norite SC
f71bdd0962 Create GPUTextureEditor.cs 2025-05-13 01:13:16 +02:00
xxSeys1
47a6da9e40 add editor option for disabled transform gizmo brightness 2025-04-27 15:56:34 +02:00
xxSeys1
1704cfba4d do not clear user search on script reload 2025-04-25 18:32:05 +02:00
Chandler Cox
40dae18b76 Add new issue and request templates. 2025-04-24 18:48:29 -05:00
84ada18299 Fix unlock mouse hotkey not unlocking CursorLockMode.Locked cursor 2025-04-21 23:13:23 +03:00
635fe8017e Fix EditorViewport buttons activating items on scene 2025-04-21 23:13:23 +03:00
834380ff05 Cleanup 2025-04-21 23:13:23 +03:00
dd65fc2289 Implement Wayland text clipboard data handling 2025-04-21 23:13:23 +03:00
86125bb625 Add support for VK_EXT_metal_surface extension 2025-04-21 23:13:23 +03:00
09a9d8b380 Update volk to 1.4.304 2025-04-21 23:13:23 +03:00
86b223ec93 Fix mouse relative mode activation triggering mouse move events on Mac 2025-04-21 23:13:23 +03:00
78f6080321 Initial support for building and running SDL platform on macOS 2025-04-21 23:13:23 +03:00
c7be6f6e0e Fix VC++ project file building on macOS Rider 2025-04-20 01:14:51 +03:00
c40c31fbb7 Reduce lock usage during window events 2025-04-19 21:14:13 +03:00
f5fbc1e32d Fix handling of WindowsManager locks 2025-04-19 21:14:13 +03:00
0a20378acd Handle Wayland dragging actions ending prematurely 2025-04-19 21:14:12 +03:00
d4e87877b6 Fix editor viewport activating while dragging a window 2025-04-19 21:14:12 +03:00
7eb7236b8a Fix occluded or hidden windows causing the engine to freeze on Wayland 2025-04-19 21:14:11 +03:00
dc0e4ffce2 Allow context menu to show when activating scene tree with right click 2025-04-19 21:14:11 +03:00
86fe93943d Fix crash when relative mode was left active on removed window 2025-04-19 21:14:10 +03:00
3258113ef8 Ensure mouse position is up-to-date during button down events 2025-04-19 21:14:10 +03:00
ebf3999cfe Fix rubber band selector activating outside of the viewport
This usually happens while trying to drag the window from window handle
2025-04-19 21:14:09 +03:00
a1ccbbb5b9 Use sensible window minimum size limits in editor windows 2025-04-19 21:14:09 +03:00
35072c40d8 Fix build on Linux 2025-04-19 21:14:08 +03:00
5c51021388 Fix merge 2025-04-19 21:14:08 +03:00
95fd527515 Apply drag and drop styling on refactored WindowDragHelper
Reapplies changes from commit 38b00f458c
2025-04-19 21:14:07 +03:00
113d851cea Fix cursor escaping constrained area when initially outside on Windows 2025-04-19 21:14:07 +03:00
72f0c460f9 Refix dragged maximized window generating wrong mouse position events 2025-04-19 21:14:06 +03:00
13ddd15b44 Focus viewports earlier to fix CursorLockMode not always activating 2025-04-19 21:14:06 +03:00
c9e24aaf5f Fix documentation generation 2025-04-19 21:14:05 +03:00
68c0ac0ffc Fix cursor locking bounds calculation 2025-04-19 21:14:05 +03:00
bebda275a9 Fix crash when Game viewport was hidden 2025-04-19 21:14:04 +03:00
287eaae850 Fix X11 external drag and drop not releasing consistently 2025-04-19 21:14:04 +03:00
7e59c3b9a7 Fix restoring locked cursor state when window gains focus again 2025-04-19 21:14:03 +03:00
38658a5b8c Fix CursorLockMode.Locked not working 2025-04-19 21:14:02 +03:00
88c75b8672 Fix dragged maximized window generating wrong mouse position events 2025-04-19 21:14:02 +03:00
17ab1e6830 Fix window handle clicking to not restore window from maximized state 2025-04-19 21:14:01 +03:00
1f45110e5f Fix rubber band selector activating when using Alt-key to orbit 2025-04-19 21:14:01 +03:00
5401166a07 Fix error when entering playmode while holding right mouse button 2025-04-19 21:14:00 +03:00
bfa8188782 Fix accepting drag and drop for files in Wayland 2025-04-19 21:14:00 +03:00
e777a71784 Fix error while dragging files around Content window 2025-04-19 21:13:59 +03:00
c13e91a0d0 Release rubber band selection when viewport starts controlling the view 2025-04-19 21:13:59 +03:00
aac5d57352 Update SDL to 3.2.10 2025-04-19 21:13:58 +03:00
ceca13c7b6 Avoid showing tooltips in inactive windows 2025-04-19 21:13:58 +03:00
2905470330 Update SDL3 to 3.2.4 2025-04-19 21:13:57 +03:00
2c17033822 Fix window dragging when not supported by Wayland compositor
(cherry picked from commit 3554747a67)
2025-04-19 21:13:57 +03:00
0a4cb9e9b1 Show current display server in Editor window tooltip
(cherry picked from commit 62968dd437)
2025-04-19 21:13:56 +03:00
096651f4c1 Properly mark floating windows with transparency support
(cherry picked from commit c660fac524)
2025-04-19 21:13:56 +03:00
275a08506b Enable transparency support in Vulkan swapchains
(cherry picked from commit 431a69e357)
2025-04-19 21:13:55 +03:00
4cd61cb381 Fix compilation for game builds
(cherry picked from commit f4fcc07288)
2025-04-19 21:13:54 +03:00
9ad1147581 Fix cloning SDL repository 2025-04-19 21:13:54 +03:00
35e09def1b Fix text input not working on X11 2025-04-19 21:13:53 +03:00
0469607a71 Fix button latching on Windows after drag and drop operation 2025-04-19 21:13:53 +03:00
d115d22ee6 Implement new window dragging system 2025-04-19 21:13:52 +03:00
8120ae621d Fix mouse resetting issues after ending relative mode 2025-04-19 21:13:52 +03:00
f873c2fa9f Fix frame stutter when window is focused 2025-04-19 21:13:51 +03:00
c3ffbe2f42 Fix error when docking to sides of tabbed panel 2025-04-19 21:13:51 +03:00
55a0a39881 Cleanup Linux SDL implementation 2025-04-19 21:13:50 +03:00
592215dd30 Support compiling third party library C files as C code 2025-04-19 21:13:50 +03:00
ef0c2a2785 Implement Wayland protocols module and file generation 2025-04-19 21:13:49 +03:00
37979e452a Fix mouse warping after ending relative mode 2025-04-19 21:13:49 +03:00
e9671bb727 Add git fetch method for dependencies 2025-04-19 21:13:48 +03:00
aa328bd591 Fix window ShowInTaskbar setting 2025-04-19 21:13:48 +03:00
188e4313f9 Fix various issues with child window positioning 2025-04-19 21:13:47 +03:00
df02c70e31 Add Window.IsAlwaysOnTop property 2025-04-19 21:13:47 +03:00
257f54b323 Use SDL locale 2025-04-19 21:13:46 +03:00
fb4b5b2575 Allow window with single tab to be dragged from tab area 2025-04-19 21:13:46 +03:00
4e1251276d Fix ValueBox mouse position resetting after releasing the button 2025-04-19 21:13:45 +03:00
a7b200dc57 Fix SDL build process on Linux 2025-04-19 21:13:44 +03:00
8cadbae80e Update SDL to 3.2.0 2025-04-19 21:13:44 +03:00
c3bae49aae Force cursor to center of Game Window when tab handle is clicked 2025-04-19 21:13:43 +03:00
Chandler Cox
6fa4fc6149 Fix rotation using SDL 2025-04-19 21:13:43 +03:00
f1ffe1acaa Fix Linux compilation without SDL 2025-04-19 21:13:42 +03:00
5c9ddf7f00 Fix compilation 2025-04-19 21:13:42 +03:00
431767a150 Update SDL3 2025-04-19 21:13:41 +03:00
8ba4e442a6 Fix compilation issues 2025-04-19 21:13:41 +03:00
2f8d19c267 Fix windows not being hidden initially 2025-04-19 21:13:40 +03:00
f2fd98f742 Fix parent window position handling with popup/tooltip windows 2025-04-19 21:13:40 +03:00
3ce35d6e81 Fix compilation errors in other platforms 2025-04-19 21:13:39 +03:00
796dbaa836 Fix CI for Linux 2025-04-19 21:13:39 +03:00
84b209ec7f Prevent building with SDL in unsupported platforms 2025-04-19 21:13:38 +03:00
fa976b34dc Fallback to X11 message box implementation when SDL fails 2025-04-19 21:13:38 +03:00
e7cda362b7 Fix popup and context menus not working on Wayland 2025-04-19 21:13:37 +03:00
a41a09c162 Hide warnings for unsupported SDL operations on Wayland 2025-04-19 21:13:37 +03:00
e82f84f0ab Log a warning for not implemented Wayland functionality 2025-04-19 21:13:36 +03:00
f1d387ceea Fix compilation in Linux 2025-04-19 21:13:36 +03:00
3893d4d1f8 Enable warning sound in question dialogs 2025-04-19 21:13:35 +03:00
cf7ac50faf Enable modern Windows dialog boxes 2025-04-19 21:13:35 +03:00
3f6bf15554 Implement relative mouse mode (raw input) for SDL platform 2025-04-19 21:13:34 +03:00
dac74829b4 Add flag for Window types 2025-04-19 21:13:34 +03:00
94d6f213a0 Enable native windowing system settings with SDL platform 2025-04-19 21:13:33 +03:00
8f2550ef61 Add command-line switches to force X11 and Wayland SDL drivers 2025-04-19 21:13:33 +03:00
b622a1cc5e Implement SDL platform, windowing and input handling 2025-04-19 21:13:32 +03:00
c83a3c32c7 Refactor application window class name 2025-04-19 21:13:32 +03:00
e7dcf7f7e7 Move Window related enums to separate header file 2025-04-19 21:13:31 +03:00
398785a2be Refactor Windows drag and drop implementation 2025-04-19 21:13:31 +03:00
05dba0f1f5 Refactor ScreenUtilities 2025-04-19 21:13:30 +03:00
39dbd32b2e Add more helper methods for managing Git repos 2025-04-19 21:13:30 +03:00
23a34a455a Fix centered window location on X11 2025-04-19 21:13:29 +03:00
4308328b48 Fix initial position of Tooltips 2025-04-19 21:13:29 +03:00
xxSeys1
4e44831bbe fix searchbox width 2025-04-11 19:07:39 +02:00
xxSeys1
0c1e0e48d4 always sort the search results alphabetically 2025-04-10 22:12:47 +02:00
xxSeys1
6884df02fd remove trailing . on message 2025-04-10 21:34:00 +02:00
xxSeys1
63655d18c5 add a info message on Debug Log pause on warning 2025-04-10 21:31:12 +02:00
xxSeys1
4170699348 add hint if there are no search results 2025-04-10 09:25:52 +02:00
xxSeys1
d58a9beb3d why was this not in the last commit? 2025-04-09 23:45:43 +02:00
xxSeys1
5049f3b2d8 add hint if no filters are active 2025-04-09 23:45:00 +02:00
xxSeys1
6e44eebb9e another fix 2025-04-09 17:01:17 +02:00
xxSeys1
aecbab5613 more fixes 2025-04-09 14:30:08 +02:00
xxSeys1
6bf90f29c5 fixes 2025-04-09 14:29:19 +02:00
xxSeys1
19edce1770 add controls and filter to actor toolbox search 2025-04-09 10:43:52 +02:00
Chandler Cox
e17b96b2d6 Add additional methods for layers. 2025-04-07 11:14:33 -05:00
Chandler Cox
9b6feb9367 Add Scaled Time to Material Time node. 2025-04-07 10:02:20 -05:00
xxSeys1
1dfd717093 serialize display info and color 2025-04-02 23:38:04 +02:00
xxSeys1
68ef6f08c6 minor style fixes 2025-04-02 19:40:27 +02:00
xxSeys1
a0b80c6096 add getters for more commonly used vehicle fields 2025-04-02 19:29:11 +02:00
xxSeys1
59ac8a3f60 move anti roll bars into Vehicle display group 2025-04-02 19:21:24 +02:00
xxSeys1
dd281bbca8 add wheel information debug draw 2025-04-02 19:12:36 +02:00
xxSeys1
2e48be97b6 add getter for steering 2025-04-02 17:24:13 +02:00
Andre Mohren
0b7550e5ca Implement creation of new projects from within the editor gui. 2025-04-02 15:10:11 +02:00
xxSeys1
391c67b1a9 add visibility options for the tab close button 2025-03-23 14:09:59 +01:00
xxSeys1
975cc79085 code style fixes 2025-03-16 22:18:21 +01:00
xxSeys1
468babae87 auto resize PropertiesList splitter bar based on longest text 2025-03-16 20:32:20 +01:00
xxSeys1
516d4263c9 add broken link icon 2025-02-11 23:56:28 +01:00
xxSeys1
ba35123420 add minimum tab width 2025-02-11 18:15:46 +01:00
xxSeys1
409703d675 add editor option for tab height 2025-02-11 16:39:33 +01:00
xxSeys1
570c3f7462 add option for single tab tab header bar visibility 2025-02-11 16:39:15 +01:00
Chandler Cox
42d02a9e63 Add small fade to bottom bar. 2025-02-08 18:49:04 -06:00
Chandler Cox
819c93f6fb Increase margins. 2024-12-24 14:26:59 -06:00
Chandler Cox
0c645cbc78 Allow user to add splash image to splash screen. 2024-12-24 12:12:59 -06:00
xxSeys1
e665cc7500 add safe margin
4 pixels seemed a bit much, smaller adjustments could lead to the menu still showing
2024-09-16 15:43:46 +02:00
xxSeys1
0a516ac98d make it possible to pan editor when rmb down on node 2024-09-14 15:33:07 +02:00
568 changed files with 105211 additions and 5734 deletions

42
.github/ISSUE_TEMPLATE/1-bug.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please attach any minimal reproduction projects!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the bug and what you expected to happen.
validations:
required: true
- type: textarea
id: steps-area
attributes:
label: Steps to reproduce
description: Please provide reproduction steps if possible.
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
description: What version of Flax are you running?
options:
- '1.8'
- '1.9'
- '1.10'
- '1.11'
- master branch
default: 2
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View File

@@ -0,0 +1,22 @@
name: Feature Request
description: File a feature request.
title: "[Request]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out a feature request!
- type: textarea
id: description-area
attributes:
label: Description
description: Please provide a description of the feature!
validations:
required: true
- type: textarea
id: benefits-area
attributes:
label: Benefits
description: Please provide what benefits this feature would provide to the engine!
validations:
required: true

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

@@ -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

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.

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.

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

Binary file not shown.

Binary file not shown.

View File

@@ -13,7 +13,7 @@
META_CB_BEGIN(0, Data)
float4x4 WorldMatrix;
float4x4 InvWorld;
float4x4 SVPositionToWorld;
float4x4 SvPositionToWorld;
@1META_CB_END
// Use depth buffer for per-pixel decal layering
@@ -27,12 +27,63 @@ struct MaterialInput
float3 WorldPosition;
float TwoSidedSign;
float2 TexCoord;
float4 TexCoord_DDX_DDY;
float3x3 TBN;
float4 SvPosition;
float3 PreSkinnedPosition;
float3 PreSkinnedNormal;
};
// Calculates decal texcoords for a given pixel position (sampels depth buffer and projects value to decal space).
float2 SvPositionToDecalUV(float4 svPosition)
{
float2 screenUV = svPosition.xy * ScreenSize.zw;
svPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
float4 positionHS = mul(float4(svPosition.xyz, 1), SvPositionToWorld);
float3 positionWS = positionHS.xyz / positionHS.w;
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
return positionOS.xz + 0.5f;
}
// Manually compute ddx/ddy for decal texture cooordinates to avoid the 2x2 pixels artifacts on the edges of geometry under decal
// [Reference: https://www.humus.name/index.php?page=3D&ID=84]
float4 CalculateTextureDerivatives(float4 svPosition, float2 texCoord)
{
float4 svDiffX = float4(1, 0, 0, 0);
float2 uvDiffX0 = texCoord - SvPositionToDecalUV(svPosition - svDiffX);
float2 uvDiffX1 = SvPositionToDecalUV(svPosition + svDiffX) - texCoord;
float2 dx = dot(uvDiffX0, uvDiffX0) < dot(uvDiffX1, uvDiffX1) ? uvDiffX0 : uvDiffX1;
float4 svDiffY = float4(0, 1, 0, 0);
float2 uvDiffY0 = texCoord - SvPositionToDecalUV(svPosition - svDiffY);
float2 uvDiffY1 = SvPositionToDecalUV(svPosition + svDiffY) - texCoord;
float2 dy = dot(uvDiffY0, uvDiffY0) < dot(uvDiffY1, uvDiffY1) ? uvDiffY0 : uvDiffY1;
return float4(dx, dy);
}
// Computes the mipmap level for a specific texture dimensions to be sampled at decal texture cooordinates.
// [Reference: https://hugi.scene.org/online/coding/hugi%2014%20-%20comipmap.htm]
float CalculateTextureMipmap(MaterialInput input, float2 textureSize)
{
float2 dx = input.TexCoord_DDX_DDY.xy * textureSize;
float2 dy = input.TexCoord_DDX_DDY.zw * textureSize;
float d = max(dot(dx, dx), dot(dy, dy));
return (0.5 * 0.5) * log2(d); // Hardcoded half-mip rate reduction to avoid artifacts when decal is moved over dither texture
}
float CalculateTextureMipmap(MaterialInput input, Texture2D t)
{
float2 textureSize;
t.GetDimensions(textureSize.x, textureSize.y);
return CalculateTextureMipmap(input, textureSize);
}
float CalculateTextureMipmap(MaterialInput input, TextureCube t)
{
float2 textureSize;
t.GetDimensions(textureSize.x, textureSize.y);
return CalculateTextureMipmap(input, textureSize);
}
// Transforms a vector from tangent space to world space
float3 TransformTangentVectorToWorld(MaterialInput input, float3 tangentVector)
{
@@ -116,7 +167,6 @@ Material GetMaterialPS(MaterialInput input)
}
// Input macro specified by the material: DECAL_BLEND_MODE
#define DECAL_BLEND_MODE_TRANSLUCENT 0
#define DECAL_BLEND_MODE_STAIN 1
#define DECAL_BLEND_MODE_NORMAL 2
@@ -153,7 +203,7 @@ void PS_Decal(
float2 screenUV = SvPosition.xy * ScreenSize.zw;
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
float4 positionHS = mul(float4(SvPosition.xyz, 1), SVPositionToWorld);
float4 positionHS = mul(float4(SvPosition.xyz, 1), SvPositionToWorld);
float3 positionWS = positionHS.xyz / positionHS.w;
float3 positionOS = mul(float4(positionWS, 1), InvWorld).xyz;
@@ -166,8 +216,9 @@ void PS_Decal(
materialInput.TexCoord = decalUVs;
materialInput.TwoSidedSign = 1;
materialInput.SvPosition = SvPosition;
// Build tangent to world transformation matrix
materialInput.TexCoord_DDX_DDY = CalculateTextureDerivatives(materialInput.SvPosition, materialInput.TexCoord);
// Calculate tangent-space
float3 ddxWp = ddx(positionWS);
float3 ddyWp = ddy(positionWS);
materialInput.TBN[0] = normalize(ddyWp);

View File

@@ -27,6 +27,7 @@ TextureCube EnvProbe : register(t__SRV__);
TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__);
@4// Forward Shading: Utilities
@5// Forward Shading: Shaders
@@ -147,6 +148,18 @@ void PS_Forward(
// Calculate exponential height fog
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
{
// Sample volumetric fog and mix it in
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
float3 viewVector = materialInput.WorldPosition - ViewPos;
float sceneDepth = length(viewVector);
float depthSlice = sceneDepth / ExponentialHeightFog.VolumetricFogMaxDistance;
float3 volumeUV = float3(screenUV, depthSlice);
float4 volumetricFog = VolumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0);
fog = CombineVolumetricFog(fog, volumetricFog);
}
// Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
output = float4(output.rgb * fog.a + fog.rgb, output.a);

View File

@@ -20,6 +20,8 @@ float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float4 ViewSize;
float3 ViewPadding0;
float UnscaledTimeParam;
@1META_CB_END
// Shader resources

View File

@@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
materialInput.TBN = output.TBN;
materialInput.TwoSidedSign = 1;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = Position;
materialInput.PreSkinnedPosition = position;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
materialInput.InstanceOrigin = output.InstanceOrigin;
materialInput.InstanceParams = output.InstanceParams;

View File

@@ -19,6 +19,8 @@ float4 ViewInfo;
float4 ScreenSize;
float4 TemporalAAJitter;
float4x4 InverseViewProjectionMatrix;
float3 ViewPadding0;
float UnscaledTimeParam;
@1META_CB_END
// Shader resources

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

BIN
Content/Shaders/Sky.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

@@ -73,6 +73,24 @@
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=TYPEDEF/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Abbreviations/=CCD/@EntryIndexedValue">CCD</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Abbreviations/=GPU/@EntryIndexedValue">GPU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=175CE9C669E52F4D92FD2C07848740BD/@EntryIndexedValue">&lt;NamingElement Priority="11" Title="Class and struct public fields"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="PUBLIC"&gt;&lt;type Name="class field" /&gt;&lt;type Name="struct field" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=32EB6D69783B3E4481A733193E338089/@EntryIndexedValue">&lt;NamingElement Priority="9" Title="Class and struct methods"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="member function" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=3C4E0D59F298854F9608A9B454E8FF5E/@EntryIndexedValue">&lt;NamingElement Priority="17" Title="Typedefs"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="type alias" /&gt;&lt;type Name="typedef" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=499C9026DADA2B448BCD0B2C54746A59/@EntryIndexedValue">&lt;NamingElement Priority="14" Title="Other constants"&gt;&lt;Descriptor Static="True" Constexpr="Indeterminate" Const="True" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="class field" /&gt;&lt;type Name="local variable" /&gt;&lt;type Name="struct field" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=50D2535711CE1A43A3B06EF841C36CFD/@EntryIndexedValue">&lt;NamingElement Priority="13" Title="Enum members"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="scoped enumerator" /&gt;&lt;type Name="unscoped enumerator" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=6AD3BADA1260CC4D840AB26323C51827/@EntryIndexedValue">&lt;NamingElement Priority="15" Title="Global constants"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="True" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="global variable" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=904CDCA174AACE4AA52660A247CDF9A0/@EntryIndexedValue">&lt;NamingElement Priority="7" Title="Global variables"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="global variable" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=95BCDE767C97B64DB3DAE800DBBBC758/@EntryIndexedValue">&lt;NamingElement Priority="5" Title="Parameters"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="function parameter" /&gt;&lt;type Name="lambda parameter" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=C03AE454FC2CBA43819AC75E4D6C9C8C/@EntryIndexedValue">&lt;NamingElement Priority="1" Title="Classes and structs"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="__interface" /&gt;&lt;type Name="class" /&gt;&lt;type Name="struct" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=D49E31C610641E4CAD0407DB79ACC851/@EntryIndexedValue">&lt;NamingElement Priority="8" Title="Global functions"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="global function" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=D73FBB3529BC5449B6C85BB37B26A8D4/@EntryIndexedValue">&lt;NamingElement Priority="16" Title="Namespaces"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="namespace" /&gt;&lt;type Name="namespace alias" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=DA41807CE47AEB4CBE1724C44D0B786E/@EntryIndexedValue">&lt;NamingElement Priority="6" Title="Local variables"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="local variable" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=DDF30C9A1DA74B4DBBC56D25FDF886AA/@EntryIndexedValue">&lt;NamingElement Priority="10" Title="Class and struct fields"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="class field" /&gt;&lt;type Name="struct field" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=EF70A6BF54ACE446971DDB32344C25A3/@EntryIndexedValue">&lt;NamingElement Priority="12" Title="Union members"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="union member" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CppNamingOptions/Rules/=F37818C54C323A4A80B1A478629985AE/@EntryIndexedValue">&lt;NamingElement Priority="2" Title="Enums"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="enum" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AI/@EntryIndexedValue">AI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ARGB/@EntryIndexedValue">ARGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LO/@EntryIndexedValue">LO</s:String>
@@ -213,6 +231,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=YZ/@EntryIndexedValue">YZ</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/PsiConfigurationSettingsKey/CustomLocation/@EntryValue">C:\Users\Wojtek\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v08_f9eacea9\SolutionCaches</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECpp_002ECodeStyle_002ENaming_002ECppNamingOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECpp_002ECodeStyle_002ESettingsUpgrade_002EFunctionReturnStyleSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECpp_002ECodeStyle_002ESettingsUpgrade_002ENamespaceIndentationSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>

View File

@@ -1,19 +0,0 @@
<!-- Please search existing issues for potential duplicates before filing yours:
https://github.com/flaxengine/FlaxEngine/issues?q=is%3Aissue
-->
**Issue description:**
<!-- What happened, and what was expected. -->
<!-- Log file, can be found in the project directory's `Logs` folder (optional) -->
**Steps to reproduce:**
<!-- Enter minimal reproduction steps if available. -->
**Minimal reproduction project:**
<!-- Recommended as it greatly speeds up debugging. Drag and drop a zip archive to upload it. -->
**Flax version:**
<!-- Specify version number. -->

View File

@@ -57,9 +57,9 @@ Follow the instructions below to compile and run the engine from source.
* Arch: `sudo pacman -S git git-lfs`
* `git-lfs install`
* Install the required packages:
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev zenity wayland-protocols libportal-dev`
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel zenity wayland-protocols-devel libportal`
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib zenity wayland-protocols libportal`
* Install Clang compiler (version 6 or later):
* Ubuntu: `sudo apt-get install clang lldb lld`
* Fedora: `sudo dnf install clang llvm lldb lld`

View File

@@ -117,7 +117,8 @@ namespace FlaxEditor.Content.Create
private static bool IsValid(Type type)
{
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
var controlTypes = Editor.Instance.CodeEditing.Controls.Get();
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type));
}
}

View File

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

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

@@ -18,8 +18,8 @@ namespace FlaxEditor
private readonly CustomEditorPresenter _presenter;
private CustomEditorWindow _customEditor;
public Win(CustomEditorWindow customEditor)
: base(Editor.Instance, false, ScrollBars.Vertical)
public Win(CustomEditorWindow customEditor, bool hideOnClose, ScrollBars scrollBars)
: base(Editor.Instance, hideOnClose, scrollBars)
{
Title = customEditor.GetType().Name;
_customEditor = customEditor;
@@ -64,9 +64,9 @@ namespace FlaxEditor
/// <summary>
/// Initializes a new instance of the <see cref="CustomEditorWindow"/> class.
/// </summary>
protected CustomEditorWindow()
protected CustomEditorWindow(bool hideOnClose = false, ScrollBars scrollBars = ScrollBars.Vertical)
{
_win = new Win(this);
_win = new Win(this, hideOnClose, scrollBars);
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
}

View File

@@ -749,6 +749,15 @@ namespace FlaxEditor.CustomEditors
}
}
private Actor FindActor(CustomEditor editor)
{
if (editor.Values[0] is Actor actor)
return actor;
if (editor.ParentEditor != null)
return FindActor(editor.ParentEditor);
return null;
}
private Actor FindPrefabRoot(CustomEditor editor)
{
if (editor.Values[0] is Actor actor)
@@ -767,32 +776,35 @@ namespace FlaxEditor.CustomEditors
return FindPrefabRoot(actor.Parent);
}
private SceneObject FindObjectWithPrefabObjectId(Actor actor, ref Guid prefabObjectId)
private SceneObject FindObjectWithPrefabObjectId(Actor actor, ref Guid prefabObjectId, Actor endPoint)
{
var visited = new HashSet<Actor>();
return FindObjectWithPrefabObjectId(actor, ref prefabObjectId, endPoint, visited);
}
private SceneObject FindObjectWithPrefabObjectId(Actor actor, ref Guid prefabObjectId, Actor endPoint, HashSet<Actor> visited)
{
if (visited.Contains(actor) || actor is Scene || actor == endPoint)
return null;
if (actor.PrefabObjectID == prefabObjectId)
return actor;
for (int i = 0; i < actor.ScriptsCount; i++)
{
if (actor.GetScript(i).PrefabObjectID == prefabObjectId)
{
var a = actor.GetScript(i);
if (a != null)
return a;
}
var script = actor.GetScript(i);
if (script != null && script.PrefabObjectID == prefabObjectId)
return script;
}
for (int i = 0; i < actor.ChildrenCount; i++)
{
if (actor.GetChild(i).PrefabObjectID == prefabObjectId)
{
var a = actor.GetChild(i);
if (a != null)
return a;
}
var child = actor.GetChild(i);
if (child != null && child.PrefabObjectID == prefabObjectId)
return child;
}
return null;
// Go up in the hierarchy
return FindObjectWithPrefabObjectId(actor.Parent, ref prefabObjectId, endPoint, visited);
}
/// <summary>
@@ -826,7 +838,7 @@ namespace FlaxEditor.CustomEditors
}
var prefabObjectId = referenceSceneObject.PrefabObjectID;
var prefabInstanceRef = FindObjectWithPrefabObjectId(prefabInstanceRoot, ref prefabObjectId);
var prefabInstanceRef = FindObjectWithPrefabObjectId(FindActor(this), ref prefabObjectId, prefabInstanceRoot);
if (prefabInstanceRef == null)
{
Editor.LogWarning("Missing prefab instance reference in the prefab instance. Cannot revert to it.");

View File

@@ -63,6 +63,11 @@ namespace FlaxEditor.CustomEditors
/// Indication of if the properties window is locked on specific objects.
/// </summary>
public bool LockSelection { get; set; }
/// <summary>
/// Gets the scene editing context.
/// </summary>
public ISceneEditingContext SceneContext { get; }
}
/// <summary>

View File

@@ -87,8 +87,11 @@ namespace FlaxEditor.CustomEditors
var targetTypeType = TypeUtils.GetType(targetType);
if (canUseRefPicker)
{
// TODO: add generic way of CustomEditor for ref pickers (use it on AssetRefEditor/GPUTextureEditor/...)
if (typeof(Asset).IsAssignableFrom(targetTypeType))
return new AssetRefEditor();
if (typeof(GPUTexture).IsAssignableFrom(targetTypeType))
return new GPUTextureEditor();
if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType))
return new FlaxObjectRefEditor();
}

View File

@@ -1,8 +1,5 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Actions;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.CustomEditors.Elements;
@@ -10,12 +7,14 @@ using FlaxEditor.GUI;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Tree;
using FlaxEditor.Scripting;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using FlaxEngine.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace FlaxEditor.CustomEditors.Dedicated
{
@@ -240,6 +239,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
node.TextColor = Color.OrangeRed;
node.Text = Utilities.Utils.GetPropertyNameUI(removed.PrefabObject.GetType().Name);
}
// Removed Actor
else if (editor is RemovedActorDummy removedActor)
{
node.TextColor = Color.OrangeRed;
node.Text = $"{removedActor.PrefabObject.Name} ({Utilities.Utils.GetPropertyNameUI(removedActor.PrefabObject.GetType().Name)})";
}
// Actor or Script
else if (editor.Values[0] is SceneObject sceneObject)
{
@@ -295,16 +300,40 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Not used
}
}
private class RemovedActorDummy : CustomEditor
{
/// <summary>
/// The removed prefab object (from the prefab default instance).
/// </summary>
public Actor PrefabObject;
/// <summary>
/// The prefab instance's parent.
/// </summary>
public Actor ParentActor;
/// <summary>
/// The order of the removed actor in the parent.
/// </summary>
public int OrderInParent;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
// Not used
}
}
private TreeNode ProcessDiff(CustomEditor editor, bool skipIfNotModified = true)
{
// Special case for new Script added to actor
if (editor.Values[0] is Script script && !script.HasPrefabLink)
// Special case for new Script or child actor added to actor
if ((editor.Values[0] is Script script && !script.HasPrefabLink) || (editor.Values[0] is Actor a && !a.HasPrefabLink))
return CreateDiffNode(editor);
// Skip if no change detected
var isRefEdited = editor.Values.IsReferenceValueModified;
if (!isRefEdited && skipIfNotModified)
if (!isRefEdited && skipIfNotModified && editor is not ScriptsEditor)
return null;
TreeNode result = null;
@@ -359,6 +388,44 @@ namespace FlaxEditor.CustomEditors.Dedicated
}
}
// Compare child actors for removed actors.
if (editor is ActorEditor && editor.Values.HasReferenceValue && editor.Values.ReferenceValue is Actor prefabObjectActor)
{
var thisActor = editor.Values[0] as Actor;
for (int i = 0; i < prefabObjectActor.ChildrenCount; i++)
{
var prefabActorChild = prefabObjectActor.Children[i];
if (thisActor == null)
continue;
bool isRemoved = true;
for (int j = 0; j < thisActor.ChildrenCount; j++)
{
var actorChild = thisActor.Children[j];
if (actorChild.PrefabObjectID == prefabActorChild.PrefabObjectID)
{
isRemoved = false;
break;
}
}
if (isRemoved)
{
var dummy = new RemovedActorDummy
{
PrefabObject = prefabActorChild,
ParentActor = thisActor,
OrderInParent = prefabActorChild.OrderInParent,
};
var child = CreateDiffNode(dummy);
if (result == null)
result = CreateDiffNode(editor);
result.AddChild(child);
}
}
}
if (editor is ScriptsEditor && result != null && result.ChildrenCount == 0)
return null;
return result;
}
@@ -438,6 +505,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
Presenter.BuildLayoutOnUpdate();
}
private static void GetAllPrefabObjects(List<object> objects, Actor actor)
{
objects.Add(actor);
objects.AddRange(actor.Scripts);
var children = actor.Children;
foreach (var child in children)
GetAllPrefabObjects(objects, child);
}
private void OnDiffRevert(CustomEditor editor)
{
// Special case for removed Script from actor
@@ -459,6 +535,22 @@ namespace FlaxEditor.CustomEditors.Dedicated
return;
}
// Special case for reverting removed Actors
if (editor is RemovedActorDummy removedActor)
{
Editor.Log("Reverting removed actor changes to prefab (adding it)");
var parentActor = removedActor.ParentActor;
var restored = parentActor.AddChild(removedActor.PrefabObject.GetType());
var prefabId = parentActor.PrefabID;
var prefabObjectId = removedActor.PrefabObject.PrefabObjectID;
string data = JsonSerializer.Serialize(removedActor.PrefabObject);
JsonSerializer.Deserialize(restored, data);
Presenter.Owner.SceneContext.Spawn(restored, parentActor, removedActor.OrderInParent);
Actor.Internal_LinkPrefab(FlaxEngine.Object.GetUnmanagedPtr(restored), ref prefabId, ref prefabObjectId);
return;
}
// Special case for new Script added to actor
if (editor.Values[0] is Script script && !script.HasPrefabLink)
{
@@ -470,8 +562,37 @@ namespace FlaxEditor.CustomEditors.Dedicated
return;
}
// Special case for new Actor added to actor
if (editor.Values[0] is Actor a && !a.HasPrefabLink)
{
Editor.Log("Reverting added actor changes to prefab (removing it)");
editor.RevertToReferenceValue();
// TODO: Keep previous selection.
var context = Presenter.Owner.SceneContext;
context.Select(SceneGraph.SceneGraphFactory.FindNode(a.ID));
context.DeleteSelection();
return;
}
if (Presenter.Undo != null && Presenter.Undo.Enabled)
{
var thisActor = (Actor)Values[0];
var rootActor = thisActor.IsPrefabRoot ? thisActor : thisActor.GetPrefabRoot();
var prefabObjects = new List<object>();
GetAllPrefabObjects(prefabObjects, rootActor);
using (new UndoMultiBlock(Presenter.Undo, prefabObjects, "Revert to Prefab"))
{
editor.RevertToReferenceValue();
editor.RefreshInternal();
}
}
else
{
editor.RevertToReferenceValue();
editor.RefreshInternal();
}
}
}
}

View File

@@ -13,6 +13,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
public class AudioSourceEditor : ActorEditor
{
private Label _infoLabel;
private Slider _slider;
private AudioSource.States _slideStartState;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
@@ -28,6 +30,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
// Play back slider
var sliderElement = playbackGroup.CustomContainer<Slider>();
_slider = sliderElement.CustomControl;
_slider.ThumbSize = new Float2(_slider.ThumbSize.X * 0.5f, _slider.ThumbSize.Y);
_slider.SlidingStart += OnSlidingStart;
_slider.SlidingEnd += OnSlidingEnd;
var grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl;
gridControl.ClipChildren = false;
@@ -40,6 +49,38 @@ namespace FlaxEditor.CustomEditors.Dedicated
}
}
private void OnSlidingEnd()
{
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
switch (_slideStartState)
{
case AudioSource.States.Playing:
audioSource.Play();
break;
case AudioSource.States.Paused:
case AudioSource.States.Stopped:
audioSource.Pause();
break;
default: break;
}
}
}
}
private void OnSlidingStart()
{
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
_slideStartState = audioSource.State;
}
}
}
/// <inheritdoc />
public override void Refresh()
{
@@ -51,7 +92,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
foreach (var value in Values)
{
if (value is AudioSource audioSource && audioSource.Clip)
{
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n";
_slider.Maximum = audioSource.Clip.Length;
_slider.Minimum = 0;
if (_slider.IsSliding)
{
if (audioSource.State != AudioSource.States.Playing)
{
// Play to move slider correctly
audioSource.Play();
audioSource.Time = _slider.Value;
}
else
{
audioSource.Time = _slider.Value;
}
}
else
{
_slider.Value = audioSource.Time;
}
}
}
_infoLabel.Text = text;
}

View File

@@ -0,0 +1,68 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Basic editor/viewer for <see cref="GPUTexture"/>.
/// </summary>
[CustomEditor(typeof(GPUTexture)), DefaultEditor]
public class GPUTextureEditor : CustomEditor
{
private Image _image;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
_image = new Image
{
Brush = new GPUTextureBrush(),
Size = new Float2(200, 100),
Parent = layout.ContainerControl,
};
_image.Clicked += OnImageClicked;
}
private void OnImageClicked(Image image, MouseButton button)
{
var texture = Values[0] as GPUTexture;
if (!texture || button != MouseButton.Right)
return;
var menu = new ContextMenu();
menu.AddButton("Save...", () => Screenshot.Capture(Values[0] as GPUTexture));
menu.AddButton("Enlarge", () => _image.Size *= 2);
menu.AddButton("Shrink", () => _image.Size /= 2).Enabled = _image.Height > 32;
var location = image.PointFromScreen(Input.MouseScreenPosition);
menu.Show(image, location);
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
var texture = Values[0] as GPUTexture;
((GPUTextureBrush)_image.Brush).Texture = texture;
if (texture)
{
var desc = texture.Description;
#if BUILD_RELEASE
var name = string.Empty;
#else
var name = texture.Name;
#endif
_image.TooltipText = $"{name}\nType: {texture.ResourceType}\nSize: {desc.Width}x{desc.Height}\nFormat: {desc.Format}\nMemory: {Utilities.Utils.FormatBytesCount(texture.MemoryUsage)}";
}
else
{
_image.TooltipText = "None";
}
}
}
}

View File

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

View File

@@ -36,6 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
ScriptName = scriptName;
TooltipText = "Create a new script";
DrawHighlights = false;
}
}
@@ -70,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
_addScriptsButton = new Button
{
TooltipText = "Add new scripts to the actor",
TooltipText = "Add new scripts to the actor.",
AnchorPreset = AnchorPresets.MiddleCenter,
Text = buttonText,
Parent = this,
@@ -114,7 +115,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
cm.TextChanged += text =>
{
if (!IsValidScriptName(text))
{
// Remove NewScriptItems
List<Control> newScriptItems = cm.ItemsPanel.Children.FindAll(c => c is NewScriptItem);
foreach (var item in newScriptItems)
{
cm.ItemsPanel.RemoveChild(item);
}
return;
}
if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem))
{
// If there are no visible items, that means the search failed so we can find the create script button or create one if it's the first time
@@ -876,7 +886,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Add drag button to the group
var scriptDrag = new DragImage
{
TooltipText = "Script reference",
TooltipText = "Script reference.",
AutoFocus = true,
IsScrollable = false,
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,

View File

@@ -106,7 +106,6 @@ namespace FlaxEditor.CustomEditors.Editors
_linkButton = new Button
{
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Link32),
Parent = LinkedLabel,
Width = 18,
Height = 18,
@@ -189,6 +188,7 @@ namespace FlaxEditor.CustomEditors.Editors
_linkButton.SetColors(backgroundColor);
_linkButton.BorderColor = _linkButton.BorderColorSelected = _linkButton.BorderColorHighlighted = Color.Transparent;
_linkButton.TooltipText = LinkValues ? "Unlinks scale components from uniform scaling" : "Links scale components for uniform scaling";
_linkButton.BackgroundBrush = new SpriteBrush(LinkValues ? Editor.Instance.Icons.Link32 : Editor.Instance.Icons.BrokenLink32);
}
}

View File

@@ -70,7 +70,9 @@ namespace FlaxEditor.CustomEditors.Editors
menu.ItemsContainer.RemoveChildren();
menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Paste", linkedEditor.Paste);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
b = menu.AddButton("Paste", linkedEditor.Paste);
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
menu.AddSeparator();
@@ -404,8 +406,10 @@ namespace FlaxEditor.CustomEditors.Editors
var menu = new ContextMenu();
menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste;
paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
if (_canReorder)
{
@@ -418,7 +422,8 @@ namespace FlaxEditor.CustomEditors.Editors
moveDownButton.Enabled = Index + 1 < Editor.Count;
}
menu.AddButton("Remove", OnRemoveClicked);
b = menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly && Editor._canResize;
menu.Show(panel, location);
}
@@ -741,6 +746,34 @@ namespace FlaxEditor.CustomEditors.Editors
cloned[srcIndex] = tmp;
SetValue(cloned);
}
/// <summary>
/// Duplicates the list item.
/// </summary>
/// <param name="index">The index to duplicate.</param>
public void Duplicate(int index)
{
if (IsSetBlocked)
return;
var count = Count;
var newValues = Allocate(count + 1);
var oldValues = (IList)Values[0];
for (int i = 0; i <= index; i++)
{
newValues[i] = oldValues[i];
}
newValues[index + 1] = Utilities.Utils.CloneValue(oldValues[index]);
for (int i = index + 1; i < count; i++)
{
newValues[i + 1] = oldValues[i];
}
SetValue(newValues);
}
/// <summary>
/// Shifts the specified item at the given index and moves it through the list to the other item. It supports undo.

View File

@@ -3,6 +3,7 @@
using System;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.Utilities;
namespace FlaxEditor.CustomEditors.Editors
@@ -81,9 +82,13 @@ namespace FlaxEditor.CustomEditors.Editors
private OptionType[] _options;
private ScriptType _type;
private Elements.PropertiesListElement _typeItem;
private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
/// <inheritdoc />
public override bool RevertValueWithChildren => false; // Always revert value for a whole object
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
@@ -98,7 +103,8 @@ namespace FlaxEditor.CustomEditors.Editors
_type = type;
// Type
var typeEditor = layout.ComboBox(TypeComboBoxName, "Type of the object value. Use it to change the object.");
_typeItem = layout.AddPropertyItem(TypeComboBoxName, "Type of the object value. Use it to change the object.");
var typeEditor = _typeItem.ComboBox();
for (int i = 0; i < _options.Length; i++)
{
typeEditor.ComboBox.AddItem(_options[i].Name);
@@ -126,6 +132,8 @@ namespace FlaxEditor.CustomEditors.Editors
// Value
var values = new CustomValueContainer(type, (instance, index) => instance);
if (Values.HasReferenceValue)
values.SetReferenceValue(Values.ReferenceValue);
values.AddRange(Values);
var editor = CustomEditorsUtil.CreateEditor(type);
var style = editor.Style;
@@ -170,6 +178,12 @@ namespace FlaxEditor.CustomEditors.Editors
{
base.Refresh();
// Show prefab diff when reference value type is different
var color = Color.Transparent;
if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0]?.GetType() != Values.ReferenceValue?.GetType())
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
_typeItem.Labels[0].HighlightStripColor = color;
// Check if type has been modified outside the editor (eg. from code)
if (Type != _type)
{

View File

@@ -14,6 +14,9 @@ namespace FlaxEditor.CustomEditors.GUI
public class PropertiesList : PanelWithMargins
{
// TODO: sync splitter for whole presenter
private const float SplitterPadding = 15;
private const float EditorsMinWidthRatio = 0.4f;
/// <summary>
/// The splitter size (in pixels).
@@ -25,6 +28,7 @@ namespace FlaxEditor.CustomEditors.GUI
private Rectangle _splitterRect;
private bool _splitterClicked, _mouseOverSplitter;
private bool _cursorChanged;
private bool _hasCustomSplitterValue;
/// <summary>
/// Gets or sets the splitter value (always in range [0; 1]).
@@ -66,6 +70,26 @@ namespace FlaxEditor.CustomEditors.GUI
UpdateSplitRect();
}
private void AutoSizeSplitter()
{
if (_hasCustomSplitterValue || !Editor.Instance.Options.Options.Interface.AutoSizePropertiesPanelSplitter)
return;
Font font = Style.Current.FontMedium;
float largestWidth = 0f;
for (int i = 0; i < _element.Labels.Count; i++)
{
Label currentLabel = _element.Labels[i];
Float2 dimensions = font.MeasureText(currentLabel.Text);
float width = dimensions.X + currentLabel.Margin.Left + SplitterPadding;
largestWidth = Mathf.Max(largestWidth, width);
}
SplitterValue = Mathf.Clamp(largestWidth / Width, 0, 1 - EditorsMinWidthRatio);
}
private void UpdateSplitRect()
{
_splitterRect = new Rectangle(Mathf.Clamp(_splitterValue * Width - SplitterSize * 0.5f, 0.0f, Width), 0, SplitterSize, Height);
@@ -122,6 +146,7 @@ namespace FlaxEditor.CustomEditors.GUI
SplitterValue = location.X / Width;
Cursor = CursorType.SizeWE;
_cursorChanged = true;
_hasCustomSplitterValue = true;
}
else if (_mouseOverSplitter)
{
@@ -195,6 +220,7 @@ namespace FlaxEditor.CustomEditors.GUI
// Refresh
UpdateSplitRect();
PerformLayout(true);
AutoSizeSplitter();
}
/// <inheritdoc />

View File

@@ -51,6 +51,7 @@ namespace FlaxEditor
private readonly List<EditorModule> _modules = new List<EditorModule>(16);
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit;
private string _projectToOpen;
private bool _projectIsNew;
private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f;
private Button _saveNowButton;
private Button _cancelSaveButton;
@@ -528,7 +529,11 @@ namespace FlaxEditor
var timeSinceLastSave = Time.UnscaledGameTime - _lastAutoSaveTimer;
var timeToNextSave = options.AutoSaveFrequency * 60.0f - timeSinceLastSave;
if (timeToNextSave <= 0.0f || _autoSaveNow)
if (timeToNextSave <= 0.0f && GetWindows().Any(x => x.GUI.Children.Any(c => c is GUI.ContextMenu.ContextMenuBase)))
{
// Skip aut-save if any context menu is opened to wait for user to end interaction
}
else if (timeToNextSave <= 0.0f || _autoSaveNow)
{
Log("Auto save");
_lastAutoSaveTimer = Time.UnscaledGameTime;
@@ -733,11 +738,12 @@ namespace FlaxEditor
var procSettings = new CreateProcessSettings
{
FileName = Platform.ExecutableFilePath,
Arguments = string.Format("-project \"{0}\"", _projectToOpen),
Arguments = string.Format("-project \"{0}\"" + (_projectIsNew ? " -new" : string.Empty), _projectToOpen),
ShellExecute = true,
WaitForEnd = false,
HiddenWindow = false,
};
_projectIsNew = false;
_projectToOpen = null;
Platform.CreateProcess(ref procSettings);
}
@@ -786,6 +792,24 @@ namespace FlaxEditor
}
}
/// <summary>
/// Creates the given project. Afterwards closes this project with running editor and opens the given project.
/// </summary>
/// <param name="projectFilePath">The project file path.</param>
public void NewProject(string projectFilePath)
{
if (projectFilePath == null)
{
MessageBox.Show("Missing project");
return;
}
// Cache project path and start editor exit (it will open new instance on valid closing)
_projectToOpen = StringUtils.NormalizePath(Path.GetDirectoryName(projectFilePath));
_projectIsNew = true;
Windows.MainWindow.Close(ClosingReason.User);
}
/// <summary>
/// Closes this project with running editor and opens the given project.
/// </summary>

View File

@@ -39,6 +39,7 @@ namespace FlaxEditor
public SpriteHandle Globe32;
public SpriteHandle CamSpeed32;
public SpriteHandle Link32;
public SpriteHandle BrokenLink32;
public SpriteHandle Add32;
public SpriteHandle Left32;
public SpriteHandle Right32;
@@ -94,6 +95,7 @@ namespace FlaxEditor
public SpriteHandle Search64;
public SpriteHandle Bone64;
public SpriteHandle Link64;
public SpriteHandle BrokenLink64;
public SpriteHandle Build64;
public SpriteHandle Add64;
public SpriteHandle ShipIt64;

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) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
@@ -121,7 +124,7 @@ namespace FlaxEditor.GUI.ContextMenu
}
/// <summary>
/// Shows the empty menu popup o na screen.
/// Shows the empty menu popup on a screen.
/// </summary>
/// <param name="control">The target control.</param>
/// <param name="area">The target control area to cover.</param>
@@ -256,7 +259,9 @@ namespace FlaxEditor.GUI.ContextMenu
desc.AllowMaximize = false;
desc.AllowDragAndDrop = false;
desc.IsTopmost = true;
desc.IsRegularWindow = false;
desc.Type = WindowType.Popup;
desc.Parent = parentWin.Window;
desc.Title = "ContextMenu";
desc.HasSizingFrame = false;
OnWindowCreating(ref desc);
_window = Platform.CreateWindow(ref desc);
@@ -265,6 +270,12 @@ namespace FlaxEditor.GUI.ContextMenu
_window.GotFocus += OnWindowGotFocus;
_window.LostFocus += OnWindowLostFocus;
}
#if USE_IS_FOREGROUND && USE_SDL_WORKAROUNDS
// The focus between popup and parent windows doesn't change, force hide the popup when clicked on parent
parentWin.Window.MouseDown += OnWindowMouseDown;
_window.Closed += () => parentWin.Window.MouseDown -= OnWindowMouseDown;
#endif
// Attach to the window
_parentCM = parent as ContextMenuBase;
@@ -440,6 +451,17 @@ namespace FlaxEditor.GUI.ContextMenu
}
}
#if USE_SDL_WORKAROUNDS
private void OnWindowGotFocus()
{
}
private void OnWindowMouseDown(ref Float2 mousePosition, MouseButton button, ref bool handled)
{
// The user clicked outside the popup window
Hide();
}
#else
private void OnWindowGotFocus()
{
var child = _childCM;
@@ -453,6 +475,7 @@ namespace FlaxEditor.GUI.ContextMenu
});
}
}
#endif
private void OnWindowLostFocus()
{
@@ -551,7 +574,12 @@ namespace FlaxEditor.GUI.ContextMenu
// Let root context menu to check if none of the popup windows
if (_parentCM == null && UseVisibilityControl && !IsForeground)
{
#if USE_SDL_WORKAROUNDS
if (!IsMouseOver)
Hide();
#else
Hide();
#endif
}
}
#endif

View File

@@ -326,8 +326,11 @@ namespace FlaxEditor.GUI.Dialogs
// Update eye dropper tool
if (_activeEyedropper)
{
// Try reading the color under the cursor in realtime if supported by the platform
Float2 mousePosition = Platform.MousePosition;
SelectedColor = ScreenUtilities.GetColorAt(mousePosition);
Color color = ScreenUtilities.GetColorAt(mousePosition);
if (color != Color.Transparent)
SelectedColor = color;
}
}

View File

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

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -13,12 +14,12 @@ namespace FlaxEditor.GUI.Docking
public class DockPanelProxy : ContainerControl
{
private DockPanel _panel;
private InterfaceOptions.TabCloseButtonVisibility closeButtonVisibility;
private double _dragEnterTime = -1;
#if PLATFORM_WINDOWS
private const bool HideTabForSingleTab = true;
#else
private const bool HideTabForSingleTab = false;
#endif
private float _tabHeight = Editor.Instance.Options.Options.Interface.TabHeight;
private bool _useMinimumTabWidth = Editor.Instance.Options.Options.Interface.UseMinimumTabWidth;
private float _minimumTabWidth = Editor.Instance.Options.Options.Interface.MinimumTabWidth;
private readonly bool _hideTabForSingleTab = Utilities.Utils.HideSingleTabWindowTabBars();
/// <summary>
/// The is mouse down flag (left button).
@@ -49,14 +50,19 @@ 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.
/// </summary>
public DockWindow StartDragAsyncWindow;
private Rectangle HeaderRectangle => new Rectangle(0, 0, Width, DockPanel.DefaultHeaderHeight);
private bool IsSingleFloatingWindow => HideTabForSingleTab && _panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0;
private Rectangle HeaderRectangle => new Rectangle(0, 0, Width, _tabHeight);
private bool IsSingleFloatingWindow => _hideTabForSingleTab && _panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0;
/// <summary>
/// Initializes a new instance of the <see cref="DockPanelProxy"/> class.
@@ -70,6 +76,14 @@ namespace FlaxEditor.GUI.Docking
_panel = panel;
AnchorPreset = AnchorPresets.StretchAll;
Offsets = Margin.Zero;
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
OnEditorOptionsChanged(Editor.Instance.Options.Options);
}
private void OnEditorOptionsChanged(EditorOptions options)
{
closeButtonVisibility = options.Interface.ShowTabCloseButton;
}
private DockWindow GetTabAtPos(Float2 position, out bool closeButton)
@@ -80,11 +94,11 @@ namespace FlaxEditor.GUI.Docking
var tabsCount = _panel.TabsCount;
if (tabsCount == 1)
{
var crossRect = new Rectangle(Width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
var crossRect = new Rectangle(Width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
if (HeaderRectangle.Contains(position))
{
closeButton = crossRect.Contains(position);
result = _panel.GetTab(0);
closeButton = crossRect.Contains(position) && IsCloseButtonVisible(result, closeButtonVisibility);
}
}
else
@@ -93,15 +107,17 @@ namespace FlaxEditor.GUI.Docking
for (int i = 0; i < tabsCount; i++)
{
var tab = _panel.GetTab(i);
var titleSize = tab.TitleSize;
var iconWidth = tab.Icon.IsValid ? DockPanel.DefaultButtonsSize + DockPanel.DefaultLeftTextMargin : 0;
var width = titleSize.X + DockPanel.DefaultButtonsSize + 2 * DockPanel.DefaultButtonsMargin + DockPanel.DefaultLeftTextMargin + DockPanel.DefaultRightTextMargin + iconWidth;
var tabRect = new Rectangle(x, 0, width, DockPanel.DefaultHeaderHeight);
float width = CalculateTabWidth(tab, closeButtonVisibility);
if (_useMinimumTabWidth && width < _minimumTabWidth)
width = _minimumTabWidth;
var tabRect = new Rectangle(x, 0, width, HeaderRectangle.Height);
var isMouseOver = tabRect.Contains(position);
if (isMouseOver)
{
var crossRect = new Rectangle(x + width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
closeButton = crossRect.Contains(position);
var crossRect = new Rectangle(x + width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
closeButton = crossRect.Contains(position) && IsCloseButtonVisible(tab, closeButtonVisibility);
result = tab;
break;
}
@@ -112,6 +128,24 @@ namespace FlaxEditor.GUI.Docking
return result;
}
private bool IsCloseButtonVisible(DockWindow win, InterfaceOptions.TabCloseButtonVisibility visibilityMode)
{
return visibilityMode != InterfaceOptions.TabCloseButtonVisibility.Never &&
(visibilityMode == InterfaceOptions.TabCloseButtonVisibility.Always ||
(visibilityMode == InterfaceOptions.TabCloseButtonVisibility.SelectedTab && _panel.SelectedTab == win));
}
private float CalculateTabWidth(DockWindow win, InterfaceOptions.TabCloseButtonVisibility visibilityMode)
{
var iconWidth = win.Icon.IsValid ? DockPanel.DefaultButtonsSize + DockPanel.DefaultLeftTextMargin : 0;
var width = win.TitleSize.X + DockPanel.DefaultLeftTextMargin + DockPanel.DefaultRightTextMargin + iconWidth;
if (IsCloseButtonVisible(win, visibilityMode))
width += 2 * DockPanel.DefaultButtonsMargin + DockPanel.DefaultButtonsSize;
return width;
}
private void GetTabRect(DockWindow win, out Rectangle bounds)
{
FlaxEngine.Assertions.Assert.IsTrue(_panel.ContainsTab(win));
@@ -129,10 +163,10 @@ namespace FlaxEditor.GUI.Docking
{
var tab = _panel.GetTab(i);
var titleSize = tab.TitleSize;
float width = titleSize.X + DockPanel.DefaultButtonsSize + 2 * DockPanel.DefaultButtonsMargin + DockPanel.DefaultLeftTextMargin + DockPanel.DefaultRightTextMargin;
float width = CalculateTabWidth(tab, closeButtonVisibility);
if (tab == win)
{
bounds = new Rectangle(x, 0, width, DockPanel.DefaultHeaderHeight);
bounds = new Rectangle(x, 0, width, HeaderRectangle.Height);
return;
}
x += width;
@@ -165,7 +199,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 +210,7 @@ namespace FlaxEditor.GUI.Docking
_panel.SelectTab(index - 1);
// Create docking hint window
DockHintWindow.Create(win);
WindowDragHelper.StartDragging(win, _panel.RootWindow.Window);
}
}
}
@@ -212,7 +246,7 @@ namespace FlaxEditor.GUI.Docking
{
Render2D.DrawSprite(
tab.Icon,
new Rectangle(DockPanel.DefaultLeftTextMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize),
new Rectangle(DockPanel.DefaultLeftTextMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize),
style.Foreground);
}
@@ -221,17 +255,20 @@ namespace FlaxEditor.GUI.Docking
Render2D.DrawText(
style.FontMedium,
tab.Title,
new Rectangle(DockPanel.DefaultLeftTextMargin + iconWidth, 0, Width - DockPanel.DefaultLeftTextMargin - DockPanel.DefaultButtonsSize - 2 * DockPanel.DefaultButtonsMargin, DockPanel.DefaultHeaderHeight),
new Rectangle(DockPanel.DefaultLeftTextMargin + iconWidth, 0, Width - DockPanel.DefaultLeftTextMargin - DockPanel.DefaultButtonsSize - 2 * DockPanel.DefaultButtonsMargin, HeaderRectangle.Height),
style.Foreground,
TextAlignment.Near,
TextAlignment.Center);
// Draw cross
var crossRect = new Rectangle(Width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
bool isMouseOverCross = isMouseOver && crossRect.Contains(MousePosition);
if (isMouseOverCross)
Render2D.FillRectangle(crossRect, (containsFocus ? style.BackgroundSelected : style.LightBackground) * 1.3f);
Render2D.DrawSprite(style.Cross, crossRect, isMouseOverCross ? style.Foreground : style.ForegroundGrey);
if (IsCloseButtonVisible(tab, closeButtonVisibility))
{
// Draw cross
var crossRect = new Rectangle(Width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
bool isMouseOverCross = isMouseOver && crossRect.Contains(MousePosition);
if (isMouseOverCross)
Render2D.FillRectangle(crossRect, (containsFocus ? style.BackgroundSelected : style.LightBackground) * 1.3f);
Render2D.DrawSprite(style.Cross, crossRect, isMouseOverCross ? style.Foreground : style.ForegroundGrey);
}
}
else
{
@@ -245,10 +282,14 @@ namespace FlaxEditor.GUI.Docking
// Cache data
var tab = _panel.GetTab(i);
var tabColor = Color.Black;
var titleSize = tab.TitleSize;
var iconWidth = tab.Icon.IsValid ? DockPanel.DefaultButtonsSize + DockPanel.DefaultLeftTextMargin : 0;
var width = titleSize.X + DockPanel.DefaultButtonsSize + 2 * DockPanel.DefaultButtonsMargin + DockPanel.DefaultLeftTextMargin + DockPanel.DefaultRightTextMargin + iconWidth;
var tabRect = new Rectangle(x, 0, width, DockPanel.DefaultHeaderHeight);
float width = CalculateTabWidth(tab, closeButtonVisibility);
if (_useMinimumTabWidth && width < _minimumTabWidth)
width = _minimumTabWidth;
var tabRect = new Rectangle(x, 0, width, headerRect.Height);
var isMouseOver = tabRect.Contains(MousePosition);
var isSelected = _panel.SelectedTab == tab;
@@ -275,7 +316,7 @@ namespace FlaxEditor.GUI.Docking
{
Render2D.DrawSprite(
tab.Icon,
new Rectangle(x + DockPanel.DefaultLeftTextMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize),
new Rectangle(x + DockPanel.DefaultLeftTextMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize),
style.Foreground);
}
@@ -284,27 +325,27 @@ namespace FlaxEditor.GUI.Docking
Render2D.DrawText(
style.FontMedium,
tab.Title,
new Rectangle(x + DockPanel.DefaultLeftTextMargin + iconWidth, 0, 10000, DockPanel.DefaultHeaderHeight),
new Rectangle(x + DockPanel.DefaultLeftTextMargin + iconWidth, 0, 10000, HeaderRectangle.Height),
style.Foreground,
TextAlignment.Near,
TextAlignment.Center);
// Draw cross
if (isSelected || isMouseOver)
if (IsCloseButtonVisible(tab, closeButtonVisibility))
{
var crossRect = new Rectangle(x + width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (DockPanel.DefaultHeaderHeight - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
var crossRect = new Rectangle(x + width - DockPanel.DefaultButtonsSize - DockPanel.DefaultButtonsMargin, (HeaderRectangle.Height - DockPanel.DefaultButtonsSize) / 2, DockPanel.DefaultButtonsSize, DockPanel.DefaultButtonsSize);
bool isMouseOverCross = isMouseOver && crossRect.Contains(MousePosition);
if (isMouseOverCross)
Render2D.FillRectangle(crossRect, tabColor * 1.3f);
Render2D.DrawSprite(style.Cross, crossRect, isMouseOverCross ? style.Foreground : style.ForegroundGrey);
}
// Move
// Set the start position for the next tab
x += width;
}
// Draw selected tab strip
Render2D.FillRectangle(new Rectangle(0, DockPanel.DefaultHeaderHeight - 2, Width, 2), containsFocus ? style.BackgroundSelected : style.BackgroundNormal);
Render2D.FillRectangle(new Rectangle(0, HeaderRectangle.Height - 2, Width, 2), containsFocus ? style.BackgroundSelected : style.BackgroundNormal);
}
}
@@ -355,6 +396,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 +483,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)
{
@@ -522,7 +578,7 @@ namespace FlaxEditor.GUI.Docking
if (IsSingleFloatingWindow)
rect = new Rectangle(0, 0, Width, Height);
else
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
rect = new Rectangle(0, HeaderRectangle.Height, Width, Height - HeaderRectangle.Height);
}
private DragDropEffect TrySelectTabUnderLocation(ref Float2 location)

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>

View File

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

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

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

@@ -51,6 +51,11 @@ namespace FlaxEditor.GUI
/// </summary>
public float SortScore;
/// <summary>
/// Wether the query highlights should be draw.
/// </summary>
public bool DrawHighlights = true;
/// <summary>
/// Occurs when items gets clicked by the user.
/// </summary>
@@ -165,7 +170,7 @@ namespace FlaxEditor.GUI
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted);
// Draw all highlights
if (_highlights != null)
if (DrawHighlights && _highlights != null)
{
var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++)
@@ -514,20 +519,15 @@ namespace FlaxEditor.GUI
var items = ItemsPanel.Children;
for (int i = 0; i < items.Count; i++)
{
if (items[i] is Item item && item.Visible)
var currentItem = items[i];
if (currentItem is Item item && item.Visible)
result.Add(item);
}
if (_categoryPanels != null)
{
for (int i = 0; i < _categoryPanels.Count; i++)
else if (currentItem is DropPanel category && (!ignoreFoldedCategories || !category.IsClosed) && currentItem.Visible)
{
var category = _categoryPanels[i];
if (!category.Visible || (ignoreFoldedCategories && category is DropPanel panel && panel.IsClosed))
continue;
for (int j = 0; j < category.Children.Count; j++)
{
if (category.Children[j] is Item item2 && item2.Visible)
result.Add(item2);
if (category.Children[j] is Item categoryItem && categoryItem.Visible)
result.Add(categoryItem);
}
}
}
@@ -591,10 +591,6 @@ namespace FlaxEditor.GUI
var items = GetVisibleItems(!controlDown);
var focusedIndex = items.IndexOf(focusedItem);
// If the user hasn't selected anything yet and is holding control, focus first folded item
if (focusedIndex == -1 && controlDown)
focusedIndex = GetVisibleItems(true).Count - 1;
int delta = key == KeyboardKeys.ArrowDown ? -1 : 1;
int nextIndex = Mathf.Wrap(focusedIndex - delta, 0, items.Count - 1);
var nextItem = items[nextIndex];

View File

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

View File

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

View File

@@ -11,6 +11,9 @@ namespace FlaxEditor.GUI
/// <seealso cref="FlaxEngine.GUI.Panel" />
public class NavigationBar : Panel
{
private float _toolstripHeight = 0;
private Margin _toolstripMargin;
/// <summary>
/// The default buttons margin.
/// </summary>
@@ -50,9 +53,42 @@ namespace FlaxEditor.GUI
{
if (toolstrip == null)
return;
if (_toolstripHeight <= 0.0f)
{
// Cache initial toolstrip state
_toolstripHeight = toolstrip.Height;
_toolstripMargin = toolstrip.ItemsMargin;
}
// Control toolstrip bottom margin to prevent navigation bar scroll going over the buttons
var toolstripLocked = toolstrip.IsLayoutLocked;
toolstrip.IsLayoutLocked = true;
var toolstripHeight = _toolstripHeight;
var toolstripMargin = _toolstripMargin;
if (HScrollBar.Visible)
{
float scrollMargin = 8;
toolstripHeight += scrollMargin;
toolstripMargin.Bottom += scrollMargin;
}
toolstrip.Height = toolstripHeight;
toolstrip.IsLayoutLocked = toolstripLocked;
toolstrip.ItemsMargin = toolstripMargin;
var lastToolstripButton = toolstrip.LastButton;
var parentSize = Parent.Size;
Bounds = new Rectangle(lastToolstripButton.Right + 8.0f, 0, parentSize.X - X - 8.0f, toolstrip.Height);
}
/// <inheritdoc />
public override void PerformLayout(bool force = false)
{
base.PerformLayout(force);
// Stretch excluding toolstrip margin to fill the space
if (Parent is ToolStrip toolStrip)
Height = toolStrip.Height;
}
}
}

View File

@@ -130,6 +130,10 @@ namespace FlaxEditor.GUI
/// <returns>Created popup.</returns>
public static RenamePopup Show(Control control, Rectangle area, string value, bool isMultiline)
{
// hardcoded flushing layout for tree controls
if (control is Tree.TreeNode treeNode && treeNode.ParentTree != null)
treeNode.ParentTree.FlushPendingPerformLayout();
// Calculate the control size in the window space to handle scaled controls
var upperLeft = control.PointToWindow(area.UpperLeft);
var bottomRight = control.PointToWindow(area.BottomRight);

View File

@@ -10,6 +10,7 @@ using System.Text;
using FlaxEditor.GUI.Timeline.Undo;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Timeline.Tracks
@@ -54,7 +55,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var paramTypeName = LoadName(stream);
e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName);
if (e.EventParamsTypes[i] == null)
{
Editor.LogError($"Unknown type {paramTypeName}.");
isInvalid = true;
}
}
if (isInvalid)
@@ -82,7 +86,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++)
{
stream.Read(dataBuffer, 0, e.EventParamsSizes[j]);
key.Parameters[j] = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j]);
key.Parameters[j] = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j], e.EventParamsSizes[j]);
}
events[i] = new KeyframesEditor.Keyframe
@@ -125,8 +129,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++)
{
Marshal.StructureToPtr(key.Parameters[j], ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.EventParamsSizes[j]);
Utilities.Utils.StructureToByteArray(key.Parameters[j], e.EventParamsSizes[j], ptr, dataBuffer);
stream.Write(dataBuffer, 0, e.EventParamsSizes[j]);
}
}
@@ -153,7 +156,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
/// <summary>
/// The event key data.
/// </summary>
public struct EventKey
public struct EventKey : ICloneable
{
/// <summary>
/// The parameters values.
@@ -178,6 +181,26 @@ namespace FlaxEditor.GUI.Timeline.Tracks
sb.Append(')');
return sb.ToString();
}
/// <inheritdoc />
public object Clone()
{
if (Parameters == null)
return new EventKey();
// Deep clone parameter values (especially boxed value types need to be duplicated to avoid referencing the same ones)
var parameters = new object[Parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var p = Parameters[i];
if (p == null || p is FlaxEngine.Object)
parameters[i] = Parameters[i];
else
parameters[i] = JsonSerializer.Deserialize(JsonSerializer.Serialize(p), p.GetType());
}
return new EventKey { Parameters = parameters };
}
}
/// <inheritdoc />
@@ -234,6 +257,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var time = Timeline.CurrentTime;
if (!TryGetValue(out var value))
value = Events.Evaluate(time);
value = ((ICloneable)value).Clone();
// Find event at the current location
for (int i = Events.Keyframes.Count - 1; i >= 0; i--)

View File

@@ -77,7 +77,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
{
var time = stream.ReadSingle();
stream.Read(dataBuffer, 0, e.ValueSize);
var value = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), propertyType);
var value = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), propertyType, e.ValueSize);
keyframes[i] = new KeyframesEditor.Keyframe
{
@@ -142,8 +142,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int i = 0; i < keyframes.Count; i++)
{
var keyframe = keyframes[i];
Marshal.StructureToPtr(keyframe.Value, ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.ValueSize);
Utilities.Utils.StructureToByteArray(keyframe.Value, e.ValueSize, ptr, dataBuffer);
stream.Write(keyframe.Time);
stream.Write(dataBuffer);
}

View File

@@ -13,15 +13,7 @@ namespace FlaxEditor.GUI
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public class ToolStrip : ContainerControl
{
/// <summary>
/// The default margin vertically.
/// </summary>
public const int DefaultMarginV = 1;
/// <summary>
/// The default margin horizontally.
/// </summary>
public const int DefaultMarginH = 2;
private Margin _itemsMargin;
/// <summary>
/// Event fired when button gets clicked with the primary mouse button.
@@ -66,10 +58,26 @@ namespace FlaxEditor.GUI
}
}
/// <summary>
/// Gets or sets the space around items.
/// </summary>
public Margin ItemsMargin
{
get => _itemsMargin;
set
{
if (_itemsMargin != value)
{
_itemsMargin = value;
PerformLayout();
}
}
}
/// <summary>
/// Gets the height for the items.
/// </summary>
public float ItemsHeight => Height - 2 * DefaultMarginV;
public float ItemsHeight => Height - _itemsMargin.Height;
/// <summary>
/// Initializes a new instance of the <see cref="ToolStrip"/> class.
@@ -82,6 +90,7 @@ namespace FlaxEditor.GUI
AnchorPreset = AnchorPresets.HorizontalStretchTop;
BackgroundColor = Style.Current.LightBackground;
Offsets = new Margin(0, 0, y, height * Editor.Instance.Options.Options.Interface.IconsScale);
_itemsMargin = new Margin(2, 2, 1, 1);
}
/// <summary>
@@ -161,7 +170,7 @@ namespace FlaxEditor.GUI
protected override void PerformLayoutBeforeChildren()
{
// Arrange controls
float x = DefaultMarginH;
float x = _itemsMargin.Left;
float h = ItemsHeight;
for (int i = 0; i < _children.Count; i++)
{
@@ -169,8 +178,8 @@ namespace FlaxEditor.GUI
if (c.Visible)
{
var w = c.Width;
c.Bounds = new Rectangle(x, DefaultMarginV, w, h);
x += w + DefaultMarginH;
c.Bounds = new Rectangle(x, _itemsMargin.Top, w, h);
x += w + _itemsMargin.Width;
}
}
}

View File

@@ -41,6 +41,7 @@ namespace FlaxEditor.GUI.Tree
private Margin _margin;
private bool _autoSize = true;
private bool _deferLayoutUpdate = false;
private TreeNode _lastSelectedNode;
/// <summary>
/// The TreeNode that is being dragged over. This could have a value when not dragging.
@@ -67,7 +68,7 @@ namespace FlaxEditor.GUI.Tree
/// Gets the first selected node or null.
/// </summary>
public TreeNode SelectedNode => Selection.Count > 0 ? Selection[0] : null;
/// <summary>
/// Allow nodes to Draw the root tree line.
/// </summary>
@@ -364,6 +365,19 @@ namespace FlaxEditor.GUI.Tree
BulkSelectUpdateExpanded(false);
}
/// <summary>
/// Flushes any pending layout perming action that has been delayed until next update to optimize performance of the complex tree hierarchy.
/// </summary>
public void FlushPendingPerformLayout()
{
if (_deferLayoutUpdate)
{
base.PerformLayout();
AfterDeferredLayout?.Invoke();
_deferLayoutUpdate = false;
}
}
/// <inheritdoc />
public override void PerformLayout(bool force = false)
{
@@ -378,25 +392,31 @@ namespace FlaxEditor.GUI.Tree
public override void Update(float deltaTime)
{
if (_deferLayoutUpdate)
{
base.PerformLayout();
AfterDeferredLayout?.Invoke();
_deferLayoutUpdate = false;
}
FlushPendingPerformLayout();
var window = Root;
bool shiftDown = window.GetKey(KeyboardKeys.Shift);
bool keyUpArrow = window.GetKey(KeyboardKeys.ArrowUp);
bool keyDownArrow = window.GetKey(KeyboardKeys.ArrowDown);
var node = SelectedNode;
// Use last selection for last selected node if sift is down
if (Selection.Count < 2)
_lastSelectedNode = null;
else if (shiftDown)
_lastSelectedNode ??= Selection[^1];
// Skip root to prevent blocking input
if (_lastSelectedNode != null && _lastSelectedNode.IsRoot)
_lastSelectedNode = null;
var node = _lastSelectedNode ?? SelectedNode;
// Check if has focus and if any node is focused and it isn't a root
if (ContainsFocus && node != null && node.AutoFocus)
{
var window = Root;
if (window.GetKeyDown(KeyboardKeys.ArrowUp) || window.GetKeyDown(KeyboardKeys.ArrowDown))
_keyUpdateTime = KeyUpdateTimeout;
if (_keyUpdateTime >= KeyUpdateTimeout && window is WindowRootControl windowRoot && windowRoot.Window.IsFocused)
{
bool keyUpArrow = window.GetKey(KeyboardKeys.ArrowUp);
bool keyDownArrow = window.GetKey(KeyboardKeys.ArrowDown);
// Check if arrow flags are different
if (keyDownArrow != keyUpArrow)
{
@@ -406,24 +426,38 @@ namespace FlaxEditor.GUI.Tree
Assert.AreNotEqual(-1, myIndex);
// Up
TreeNode toSelect = null;
List<TreeNode> toSelect = new List<TreeNode>();
if (shiftDown && _supportMultiSelect)
{
toSelect.AddRange(Selection);
}
if (keyUpArrow)
{
if (myIndex == 0)
{
// Select parent
toSelect = parentNode;
if (toSelect.Contains(parentNode))
toSelect.Remove(node);
else if (parentNode != null)
toSelect.Add(parentNode);
_lastSelectedNode = parentNode;
}
else
{
// Select previous parent child
toSelect = nodeParent.GetChild(myIndex - 1) as TreeNode;
var select = nodeParent.GetChild(myIndex - 1) as TreeNode;
// Select last child if is valid and expanded and has any children
if (toSelect != null && toSelect.IsExpanded && toSelect.HasAnyVisibleChild)
if (select != null && select.IsExpanded && select.HasAnyVisibleChild)
{
toSelect = toSelect.GetChild(toSelect.ChildrenCount - 1) as TreeNode;
select = select.GetChild(select.ChildrenCount - 1) as TreeNode;
}
if (select == null || toSelect.Contains(select))
toSelect.Remove(node);
else
toSelect.Add(select);
_lastSelectedNode = select;
}
}
// Down
@@ -432,32 +466,48 @@ namespace FlaxEditor.GUI.Tree
if (node.IsExpanded && node.HasAnyVisibleChild)
{
// Select the first child
toSelect = node.GetChild(0) as TreeNode;
var select = node.GetChild(0) as TreeNode;
if (select == null || toSelect.Contains(select))
toSelect.Remove(node);
else
toSelect.Add(select);
_lastSelectedNode = select;
}
else if (myIndex == nodeParent.ChildrenCount - 1)
{
// Select next node after parent
while (parentNode != null && toSelect == null)
TreeNode select = null;
while (parentNode != null && select == null)
{
int parentIndex = parentNode.IndexInParent;
if (parentIndex != -1 && parentIndex < parentNode.Parent.ChildrenCount - 1)
{
toSelect = parentNode.Parent.GetChild(parentIndex + 1) as TreeNode;
select = parentNode.Parent.GetChild(parentIndex + 1) as TreeNode;
}
parentNode = parentNode.Parent as TreeNode;
}
if (select == null || toSelect.Contains(select))
toSelect.Remove(node);
else
toSelect.Add(select);
_lastSelectedNode = select;
}
else
{
// Select next parent child
toSelect = nodeParent.GetChild(myIndex + 1) as TreeNode;
var select = nodeParent.GetChild(myIndex + 1) as TreeNode;
if (select == null || toSelect.Contains(select))
toSelect.Remove(node);
else
toSelect.Add(select);
_lastSelectedNode = select;
}
}
if (toSelect != null && toSelect.AutoFocus)
if (toSelect.Count > 0)
{
// Select
Select(toSelect);
toSelect.Focus();
_lastSelectedNode?.Focus();
}
// Reset time

View File

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

View File

@@ -1,9 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Options;
using FlaxEditor.SceneGraph;
using FlaxEngine;
using System;
namespace FlaxEditor.Gizmo
{
@@ -21,12 +19,16 @@ namespace FlaxEditor.Gizmo
private MaterialInstance _materialAxisY;
private MaterialInstance _materialAxisZ;
private MaterialInstance _materialAxisFocus;
private MaterialInstance _materialAxisLocked;
private MaterialBase _materialSphere;
// Material Parameter Names
const String _brightnessParamName = "Brightness";
const String _opacityParamName = "Opacity";
private const string _brightnessParamName = "Brightness";
private const string _opacityParamName = "Opacity";
/// <summary>
/// Used for example when the selection can't be moved because one actor is static.
/// </summary>
private bool _isDisabled;
private void InitDrawing()
{
@@ -42,7 +44,6 @@ namespace FlaxEditor.Gizmo
_materialAxisY = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisY");
_materialAxisZ = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisZ");
_materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisFocus");
_materialAxisLocked = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisLocked");
_materialSphere = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialSphere");
// Ensure that every asset was loaded
@@ -67,17 +68,42 @@ namespace FlaxEditor.Gizmo
private void OnEditorOptionsChanged(EditorOptions options)
{
float brightness = options.Visual.TransformGizmoBrightness;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
_materialAxisLocked.SetParameterValue(_brightnessParamName, brightness);
UpdateGizmoBrightness(options);
float opacity = options.Visual.TransformGizmoOpacity;
_materialAxisX.SetParameterValue(_opacityParamName, opacity);
_materialAxisY.SetParameterValue(_opacityParamName, opacity);
_materialAxisZ.SetParameterValue(_opacityParamName, opacity);
_materialAxisLocked.SetParameterValue(_opacityParamName, opacity);
}
private void UpdateGizmoBrightness(EditorOptions options)
{
_isDisabled = ShouldGizmoBeLocked();
float brightness = _isDisabled ? options.Visual.TransformGizmoBrightnessDisabled : options.Visual.TransformGizmoBrightness;
if (Mathf.NearEqual(brightness, (float)_materialAxisX.GetParameterValue(_brightnessParamName)))
return;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
}
private bool ShouldGizmoBeLocked()
{
bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode && Owner is Viewport.EditorGizmoViewport)
{
// Block editing static scene objects in main view during play mode
foreach (var obj in Editor.Instance.SceneEditing.Selection)
{
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
return gizmoLocked;
}
/// <inheritdoc />
@@ -88,20 +114,8 @@ namespace FlaxEditor.Gizmo
if (!_modelCube || !_modelCube.IsLoaded)
return;
// Find out if any of the selected objects can not be moved
bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode)
{
for (int i = 0; i < SelectionCount; i++)
{
var obj = GetSelectedObject(i);
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
// Update the gizmo brightness every frame to ensure it updates correctly
UpdateGizmoBrightness(Editor.Instance.Options.Options);
// As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order
// https://github.com/FlaxEngine/FlaxEngine/issues/680
@@ -136,37 +150,37 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialTransform = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
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);
MaterialInstance yAxisMaterialTransform = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
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);
MaterialInstance zAxisMaterialTransform = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
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);
MaterialInstance xyPlaneMaterialTransform = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
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);
MaterialInstance zxPlaneMaterialTransform = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
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);
MaterialInstance yzPlaneMaterialTransform = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center sphere
@@ -186,17 +200,17 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis
MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
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);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box
@@ -216,37 +230,37 @@ namespace FlaxEditor.Gizmo
// X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref mx1, out m3);
MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
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);
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
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);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
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);
MaterialInstance xyPlaneMaterialScale = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX;
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);
MaterialInstance zxPlaneMaterialScale = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisZ;
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);
MaterialInstance yzPlaneMaterialScale = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisY;
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box

View File

@@ -155,6 +155,16 @@ namespace FlaxEditor
private List<Widget> _widgets;
private Widget _activeWidget;
/// <summary>
/// Sets the view size.
/// </summary>
/// <param name="size">The new size.</param>
public void SetViewSize(Float2 size)
{
_view.Size = size;
_view.PerformLayout();
}
/// <summary>
/// True if enable displaying UI editing background and grid elements.
/// </summary>

View File

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

View File

@@ -11,6 +11,7 @@
#include "Engine/Scripting/ManagedCLR/MClass.h"
#include "Engine/Scripting/ManagedCLR/MException.h"
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Content/Assets/VisualScript.h"
#include "Engine/Content/Content.h"
#include "Engine/CSG/CSGBuilder.h"
@@ -622,6 +623,14 @@ void ManagedEditor::WipeOutLeftoverSceneObjects()
ObjectsRemovalService::Flush();
}
Array<Window*> ManagedEditor::GetWindows()
{
WindowsManager::WindowsLocker.Lock();
auto result = WindowsManager::Windows;
WindowsManager::WindowsLocker.Unlock();
return result;
}
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 Array<Window*> GetWindows();
private:
void OnEditorAssemblyLoaded(MAssembly* assembly);

View File

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

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));

View File

@@ -254,18 +254,29 @@ namespace FlaxEditor.Modules
PrefabApplying?.Invoke(prefab, instance);
// When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff)
Actor prefabRoot = null;
var originalTransform = instance.LocalTransform;
var originalName = instance.Name;
if (instance.IsPrefabRoot && instance.HasScene)
if (instance.HasScene)
{
instance.LocalTransform = prefab.GetDefaultInstance().Transform;
instance.Name = prefab.GetDefaultInstance().Name;
prefabRoot = instance.GetPrefabRoot();
if (prefabRoot != null && prefabRoot.IsPrefabRoot && instance.HasScene)
{
var defaultInstance = prefab.GetDefaultInstance();
originalTransform = prefabRoot.LocalTransform;
originalName = prefabRoot.Name;
prefabRoot.LocalTransform = defaultInstance.Transform;
prefabRoot.Name = defaultInstance.Name;
}
}
// Call backend
var failed = PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance));
instance.LocalTransform = originalTransform;
instance.Name = originalName;
if (prefabRoot != null)
{
prefabRoot.LocalTransform = originalTransform;
prefabRoot.Name = originalName;
}
if (failed)
throw new Exception("Failed to apply the prefab. See log to learn more.");

View File

@@ -673,6 +673,7 @@ namespace FlaxEditor.Modules
pasteAction.Do(out _, out var nodeParents);
// Select spawned objects (parents only)
newSelection.Clear();
newSelection.AddRange(nodeParents);
var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo);
selectAction.Do();

View File

@@ -568,6 +568,10 @@ namespace FlaxEditor.Modules
return;
}
// Skip if already added
if (SceneGraphFactory.Nodes.ContainsKey(actor.ID))
return;
var node = SceneGraphFactory.BuildActorNode(actor);
if (node != null)
{

View File

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

View File

@@ -54,6 +54,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing
case CodeEditorTypes.VS2022:
Name = "Visual Studio 2022";
break;
case CodeEditorTypes.VS2026:
Name = "Visual Studio 2026";
break;
case CodeEditorTypes.VSCode:
Name = "Visual Studio Code";
break;
@@ -110,6 +113,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
case CodeEditorTypes.VS2017:
case CodeEditorTypes.VS2019:
case CodeEditorTypes.VS2022:
case CodeEditorTypes.VS2026:
// TODO: finish dynamic files adding to the project
//Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync();
break;

View File

@@ -16,7 +16,6 @@ using FlaxEditor.Windows;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using DockHintWindow = FlaxEditor.GUI.Docking.DockHintWindow;
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
using FlaxEditor.Content.Settings;
using FlaxEditor.Options;
@@ -29,6 +28,40 @@ namespace FlaxEditor.Modules
/// <seealso cref="FlaxEditor.Modules.EditorModule" />
public sealed class UIModule : EditorModule
{
private class MainWindowDecorations : WindowDecorations
{
public MainWindowDecorations(RootControl window, bool iconOnly)
: base(window, iconOnly)
{
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (base.OnKeyDown(key))
return true;
// Fallback to the edit window for shortcuts
var editor = Editor.Instance;
return editor.Windows.EditWin.InputActions.Process(editor, this, key);
}
/// <inheritdoc />
public override void DrawBorders()
{
// Draw main window borders if using a custom style
var win = RootWindow.Window;
if (win.IsMaximized)
return;
var color = Editor.Instance.UI.StatusBar.StatusColor;
var rect = new Rectangle(0.5f, 0.5f, Parent.Width - 1.0f, Parent.Height - 1.0f - StatusBar.DefaultHeight);
Render2D.DrawLine(rect.UpperLeft, rect.UpperRight, color);
Render2D.DrawLine(rect.UpperLeft, rect.BottomLeft, color);
Render2D.DrawLine(rect.UpperRight, rect.BottomRight, color);
}
}
private Label _progressLabel;
private ProgressBar _progressBar;
private Button _outputLogButton;
@@ -37,6 +70,53 @@ namespace FlaxEditor.Modules
private bool _progressFailed;
ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>();
/// <summary>
/// Defines a viewport scaling option.
/// </summary>
public class ViewportScaleOption
{
/// <summary>
/// Defines the viewport scale type.
/// </summary>
public enum ViewportScaleType
{
/// <summary>
/// Resolution.
/// </summary>
Resolution = 0,
/// <summary>
/// Aspect Ratio.
/// </summary>
Aspect = 1,
}
/// <summary>
/// The name.
/// </summary>
public string Label;
/// <summary>
/// The Type of scaling to do.
/// </summary>
public ViewportScaleType ScaleType;
/// <summary>
/// The width and height to scale by.
/// </summary>
public Int2 Size;
}
/// <summary>
/// The default viewport scaling options.
/// </summary>
public List<ViewportScaleOption> DefaultViewportScaleOptions = new List<ViewportScaleOption>();
/// <summary>
/// The user defined viewport scaling options.
/// </summary>
public List<ViewportScaleOption> CustomViewportScaleOptions = new List<ViewportScaleOption>();
private ContextMenuButton _menuFileSaveScenes;
private ContextMenuButton _menuFileReloadScenes;
@@ -97,6 +177,11 @@ namespace FlaxEditor.Modules
/// </summary>
public MainMenu MainMenu;
/// <summary>
/// The window decorations (title bar with buttons)
/// </summary>
public WindowDecorations WindowDecorations;
/// <summary>
/// The tool strip control.
/// </summary>
@@ -371,25 +456,70 @@ namespace FlaxEditor.Modules
// Update window background
mainWindow.BackgroundColor = Style.Current.Background;
InitViewportScaleOptions();
InitSharedMenus();
InitMainMenu(mainWindow);
InitToolstrip(mainWindow);
InitStatusBar(mainWindow);
InitDockPanel(mainWindow);
InitWindowDecorations(mainWindow);
Editor.Options.OptionsChanged += OnOptionsChanged;
mainWindow.PerformLayout(true);
}
// Add dummy control for drawing the main window borders if using a custom style
#if PLATFORM_WINDOWS
if (!Editor.Options.Options.Interface.UseNativeWindowSystem)
#endif
private void InitViewportScaleOptions()
{
if (DefaultViewportScaleOptions.Count == 0)
{
mainWindow.AddChild(new CustomWindowBorderControl
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Size = Float2.Zero,
Label = "Free Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(1, 1),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:9 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 9),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:10 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 10),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "1920x1080 Resolution (Full HD)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(1920, 1080),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "2560x1440 Resolution (2K)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(2560, 1440),
});
}
if (Editor.Instance.ProjectCache.TryGetCustomData("CustomViewportScalingOptions", out string data))
{
CustomViewportScaleOptions = JsonSerializer.Deserialize<List<ViewportScaleOption>>(data);
}
}
/// <summary>
/// Saves the custom viewport scaling options.
/// </summary>
public void SaveCustomViewportScalingOptions()
{
var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions);
Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions);
}
/// <inheritdoc />
@@ -410,23 +540,6 @@ namespace FlaxEditor.Modules
}
}
private class CustomWindowBorderControl : Control
{
/// <inheritdoc />
public override void Draw()
{
var win = RootWindow.Window;
if (win.IsMaximized)
return;
var color = Editor.Instance.UI.StatusBar.StatusColor;
var rect = new Rectangle(0.5f, 0.5f, Parent.Width - 1.0f, Parent.Height - 1.0f - StatusBar.DefaultHeight);
Render2D.DrawLine(rect.UpperLeft, rect.UpperRight, color);
Render2D.DrawLine(rect.UpperLeft, rect.BottomLeft, color);
Render2D.DrawLine(rect.UpperRight, rect.BottomRight, color);
}
}
/// <inheritdoc />
public override void OnEndInit()
{
@@ -458,13 +571,6 @@ namespace FlaxEditor.Modules
UpdateToolstrip();
}
/// <inheritdoc />
public override void OnExit()
{
// Cleanup dock panel hint proxy windows (Flax will destroy them by var but it's better to clear them earlier)
DockHintWindow.Proxy.Dispose();
}
private IColorPickerDialog ShowPickColorDialog(Control targetControl, Color initialValue, ColorValueBox.ColorPickerEvent colorChanged, ColorValueBox.ColorPickerClosedEvent pickerClosed, bool useDynamicEditing)
{
var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing);
@@ -518,10 +624,12 @@ namespace FlaxEditor.Modules
private void InitMainMenu(RootControl mainWindow)
{
MainMenu = new MainMenu(mainWindow)
MainMenu = new MainMenu()
{
Parent = mainWindow
};
if (Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
MainMenu.Height = 28;
var inputOptions = Editor.Options.Options.Input;
@@ -538,6 +646,7 @@ namespace FlaxEditor.Modules
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
_menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile);
cm.AddSeparator();
cm.AddButton("New project", NewProject);
cm.AddButton("Open project...", OpenProject);
cm.AddButton("Reload project", ReloadProject);
cm.AddButton("Open project folder", () => FileSystem.ShowFileExplorer(Editor.Instance.GameProject.ProjectFolderPath));
@@ -568,7 +677,7 @@ namespace FlaxEditor.Modules
if (item != null)
Editor.ContentEditing.Open(item);
});
cm.AddButton("Editor Options", () => Editor.Windows.EditorOptionsWin.Show());
cm.AddButton("Editor Options", inputOptions.EditorOptionsWindow, () => Editor.Windows.EditorOptionsWin.Show());
// Scene
MenuScene = MainMenu.AddButton("Scene");
@@ -661,6 +770,20 @@ namespace FlaxEditor.Modules
cm.AddButton("Information about Flax", () => new AboutDialog().Show());
}
private void InitWindowDecorations(RootControl mainWindow)
{
ScriptsBuilder.GetBinariesConfiguration(out _, out _, out _, out var configuration);
var driver = Platform.DisplayServer;
if (!string.IsNullOrEmpty(driver))
driver = $" ({driver})";
WindowDecorations = new MainWindowDecorations(mainWindow, !Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
{
Parent = mainWindow,
IconTooltipText = $"{mainWindow.RootWindow.Title}\nVersion {Globals.EngineVersion}\nConfiguration {configuration}\nGraphics {GPUDevice.Instance.RendererType}{driver}",
};
}
private void OnOptionsChanged(EditorOptions options)
{
var inputOptions = options.Input;
@@ -829,6 +952,17 @@ namespace FlaxEditor.Modules
MasterPanel.Offsets = new Margin(0, 0, ToolStrip.Bottom, StatusBar.Height);
}
private void NewProject()
{
// Ask user to create project file
if (FileSystem.ShowSaveFileDialog(Editor.Windows.MainWindow, null, "Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0", false, "Create project file", out var files))
return;
if (files != null && files.Length > 0)
{
Editor.NewProject(files[0]);
}
}
private void OpenProject()
{
// Ask user to select project file
@@ -1070,6 +1204,7 @@ namespace FlaxEditor.Modules
{
// Clear UI references (GUI cannot be used after window closing)
MainMenu = null;
WindowDecorations = null;
ToolStrip = null;
MasterPanel = null;
StatusBar = null;
@@ -1085,5 +1220,267 @@ namespace FlaxEditor.Modules
MenuTools = null;
MenuHelp = null;
}
internal void CreateViewportSizingContextMenu(ContextMenu vsMenu, int defaultScaleActiveIndex, int customScaleActiveIndex, bool prefabViewport, Action<ViewportScaleOption> changeView, Action<int, int> changeActiveIndices)
{
// Add default viewport sizing options
var defaultOptions = DefaultViewportScaleOptions;
for (int i = 0; i < defaultOptions.Count; i++)
{
var viewportScale = defaultOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var button = vsMenu.AddButton(viewportScale.Label);
button.CloseMenuOnClick = false;
button.Tag = viewportScale;
// No default index is active
if (defaultScaleActiveIndex == -1)
{
button.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (defaultScaleActiveIndex == i)
{
button.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
button.Clicked += () =>
{
if (button.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (cmb == button)
{
button.Icon = Style.Current.CheckBoxTick;
var index = defaultOptions.FindIndex(x => x == v);
changeActiveIndices(index, -1); // Reset custom index because default was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
}
if (defaultOptions.Count != 0)
vsMenu.AddSeparator();
// Add custom viewport options
var customOptions = CustomViewportScaleOptions;
for (int i = 0; i < customOptions.Count; i++)
{
var viewportScale = customOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var childCM = vsMenu.AddChildMenu(viewportScale.Label);
childCM.CloseMenuOnClick = false;
childCM.Tag = viewportScale;
// No custom index is active
if (customScaleActiveIndex == -1)
{
childCM.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (customScaleActiveIndex == i)
{
childCM.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
var applyButton = childCM.ContextMenu.AddButton("Apply");
applyButton.Tag = childCM.Tag = viewportScale;
applyButton.CloseMenuOnClick = false;
applyButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (child == childCM)
{
childCM.Icon = Style.Current.CheckBoxTick;
var index = customOptions.FindIndex(x => x == v);
changeActiveIndices(-1, index); // Reset default index because custom was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
var deleteButton = childCM.ContextMenu.AddButton("Delete");
deleteButton.CloseMenuOnClick = false;
deleteButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
var v = (ViewportScaleOption)childCM.Tag;
if (childCM.Icon != SpriteHandle.Invalid)
{
changeActiveIndices(-1, 0);
changeView(defaultOptions[0]);
}
customOptions.Remove(v);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
}
if (customOptions.Count != 0)
vsMenu.AddSeparator();
// Add button
var add = vsMenu.AddButton("Add...");
add.CloseMenuOnClick = false;
add.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(add, new Float2(add.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var typeLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Type",
HorizontalAlignment = TextAlignment.Near,
};
typeLabel.LocalX += 10;
typeLabel.LocalY += 35;
var typeDropdown = new Dropdown
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Items = { "Aspect", "Resolution" },
SelectedItem = "Aspect",
Visible = !prefabViewport,
Width = nameTextBox.Width
};
typeDropdown.LocalY += 35;
typeDropdown.LocalX += 100;
var whLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Width & Height",
HorizontalAlignment = TextAlignment.Near,
};
whLabel.LocalX += 10;
whLabel.LocalY += 60;
var wValue = new IntValueBox(16)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
wValue.LocalY += 60;
wValue.LocalX += 100;
var hValue = new IntValueBox(9)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
hValue.LocalY += 60;
hValue.LocalX += 165;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Submit",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleOption.ViewportScaleType type);
if (prefabViewport)
type = ViewportScaleOption.ViewportScaleType.Resolution;
var combineString = type == ViewportScaleOption.ViewportScaleType.Aspect ? ":" : "x";
var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem;
var newViewportOption = new ViewportScaleOption
{
ScaleType = type,
Label = name,
Size = new Int2(wValue.Value, hValue.Value),
};
customOptions.Add(newViewportOption);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
typeDropdown.SelectedItem = "Aspect";
hValue.Value = 9;
wValue.Value = 16;
popup.Hide();
};
};
}
}
}

View File

@@ -10,7 +10,6 @@ using System.Text;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.GUI.Dialogs;
using FlaxEditor.GUI.Docking;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEditor.Windows.Profiler;
@@ -758,17 +757,19 @@ namespace FlaxEditor.Modules
var settings = CreateWindowSettings.Default;
settings.Title = "Flax Editor";
settings.Size = Platform.DesktopSize * 0.75f;
settings.MinimumSize = new Float2(200, 150);
settings.StartPosition = WindowStartPosition.CenterScreen;
settings.ShowAfterFirstPaint = true;
#if PLATFORM_WINDOWS
if (!Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
if (Utilities.Utils.UseCustomWindowDecorations(isMainWindow: true))
{
settings.HasBorder = false;
#if PLATFORM_WINDOWS && !PLATFORM_SDL
// Skip OS sizing frame and implement it using LeftButtonHit
settings.HasSizingFrame = false;
#endif
}
#elif PLATFORM_LINUX
#if PLATFORM_LINUX && !PLATFORM_SDL
settings.HasBorder = false;
#endif
MainWindow = Platform.CreateWindow(ref settings);

View File

@@ -650,45 +650,53 @@ namespace FlaxEditor.Options
[EditorDisplay("Windows"), EditorOrder(4020)]
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Control+Comma")]
[EditorDisplay("Windows"), EditorOrder(4030)]
public InputBinding EditorOptionsWindow = new InputBinding(KeyboardKeys.Comma, KeyboardKeys.Control);
#endregion
#region Node editors
#region Node Editors
[DefaultValue(typeof(InputBinding), "Shift+W")]
[EditorDisplay("Node editors"), EditorOrder(4500)]
[EditorDisplay("Node Editors"), EditorOrder(4500)]
public InputBinding NodesAlignTop = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+A")]
[EditorDisplay("Node editors"), EditorOrder(4510)]
[EditorDisplay("Node Editors"), EditorOrder(4510)]
public InputBinding NodesAlignLeft = new InputBinding(KeyboardKeys.A, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+S")]
[EditorDisplay("Node editors"), EditorOrder(4520)]
[EditorDisplay("Node Editors"), EditorOrder(4520)]
public InputBinding NodesAlignBottom = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Shift+D")]
[EditorDisplay("Node editors"), EditorOrder(4530)]
[EditorDisplay("Node Editors"), EditorOrder(4530)]
public InputBinding NodesAlignRight = new InputBinding(KeyboardKeys.D, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "Alt+Shift+W")]
[EditorDisplay("Node editors"), EditorOrder(4540)]
[EditorDisplay("Node Editors"), EditorOrder(4540)]
public InputBinding NodesAlignMiddle = new InputBinding(KeyboardKeys.W, KeyboardKeys.Shift, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Alt+Shift+S")]
[EditorDisplay("Node editors"), EditorOrder(4550)]
[EditorDisplay("Node Editors"), EditorOrder(4550)]
public InputBinding NodesAlignCenter = new InputBinding(KeyboardKeys.S, KeyboardKeys.Shift, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Q")]
[EditorDisplay("Node editors"), EditorOrder(4560)]
[EditorDisplay("Node Editors"), EditorOrder(4560)]
public InputBinding NodesAutoFormat = new InputBinding(KeyboardKeys.Q);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Node editors"), EditorOrder(4570)]
public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Shift+Q")]
[EditorDisplay("Node Editors"), EditorOrder(4560)]
public InputBinding NodesStraightenConnections = new InputBinding(KeyboardKeys.Q, KeyboardKeys.Shift);
[DefaultValue(typeof(InputBinding), "None")]
[EditorDisplay("Node editors"), EditorOrder(4580)]
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Alt+W")]
[EditorDisplay("Node Editors"), EditorOrder(4570)]
public InputBinding NodesDistributeHorizontal = new InputBinding(KeyboardKeys.W, KeyboardKeys.Alt);
[DefaultValue(typeof(InputBinding), "Alt+A")]
[EditorDisplay("Node Editors"), EditorOrder(4580)]
public InputBinding NodesDistributeVertical = new InputBinding(KeyboardKeys.A, KeyboardKeys.Alt);
#endregion
}

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