You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 3441680 by Uriel.Doyon Added units to point light intensity, to allow the user to specify the value in candelas or lumens. New point light actors now configure the intensity in candelas by default. Replaced viewport exposure settings by an EV100 slider. Hidding the tone mapper in the show flag now still applies the exposure. Added a new AutoExposure method called EV100 which allows to specify : - MinEV100, MaxEV100 - Calibration Constnat - Exposure Compensation #jira UE-42783 Change 3454934 by Chris.Bunner Backing out changelists 3441680, 3454636 and 3454844 for the sake of integration stability. Change 3629223 by Rolando.Caloca DR - Rollback //UE4/Dev-Rendering/Engine/Source/Runtime/VulkanRHI to changelist 3627847 Change 3629708 by Rolando.Caloca DR - vk - Redo some changes from DevMobile 3601439 3604186 3606672 3617383 3617474 3617483 Change 3636145 by Chris.Bunner Linux compile fix. Change 3636198 by Chris.Bunner Include fix. Change 3636225 by Daniel.Wright Removed spammy draw event Change 3636397 by Daniel.Wright Visualize volumetric lightmaps uses 18% grey in lit mode Change 3636398 by Daniel.Wright Translucency lighting modes work with Volumetric Lightmaps * The old Indirect Lighting Cache always interpolated one sample per object, while Volumetric lightmaps operate at the frequency of the Translucency Lighting Mode (per-vertex or per-pixel) so the lighting accuracy is much higher. * The old ILC always applied the single lighting sample with a per-pixel normal, even in per-vertex lighting modes * Volumetric PerVertex NonDirectional (cheapest lit translucency) went from 74 instructions down to 42 * Volumetric Directional went from 104 up to 122 Change 3636604 by Chris.Bunner Added a material translation error on identically named/associated but differently valued parameters as this will cause one of them to be lost during parameter evaluation, the result being "random". Change 3637668 by Rolando.Caloca DR - hlslcc - Skip preprocessor when not required which reduces peak mem consumption by ~500 MB - Fix missing indexing on intrinsic return type Change 3638541 by Chris.Bunner Fixed editor materials - Skip hardcoded parameter names that we rely on being overridden when checking for non-matching duplicate parameters. Change 3638798 by Mark.Satterthwaite Rebuilt hlslcc for Mac for Rolando's 3637668 changes. Change 3638861 by Mark.Satterthwaite Missed making a log verbose in the Metal ring-buffer. Change 3639482 by Rolando.Caloca DR - vk - Minor fixes Change 3639909 by Michael.Lentine Add special case for struct needed to compile. Workaround issues in parser such that (x)[0] is replaced with x[0] and (x).a is replaced with x.a. Change 3639916 by Michael.Lentine Spelling fix. Change 3640053 by Mark.Satterthwaite Fix Desktop Forward rendering on Nvidia Metal rendering on macOS by modifying the shader and runtime to treat ForwardLocalLightBuffer data as uint rather than float and invert the use of as*() casts. Tthis is *necessary* to avoid a bug/limitation of Nvidia's current Metal shader compiler that flushes all denorm values to zero on load from any resource. AMD & iOS Metal only flush-to-zero when sampling from textures and that's what Apple regard as the expected behaviour. I have however asked them to standardise on the D3D behaviour of preserving denorms on all load, move (incl. min/max/as*()-casts) & store operations. This won't happen in the current or imminent OS/Xcode releases. Now only Intel Metal is broken and their problems run deeper. #jira UE-48881 Change 3640983 by Olaf.Piesche Cache the depth buffer collision shader for GPU particles even when simple forward is enabled, as that can be turned off at runtime. #jira UE-48799 Change 3641480 by Michael.Lentine Add min16float to FP16Math Change 3642442 by Mark.Satterthwaite Fix the native shader libraries again & undo the increase in cook time from changes to the way FShaderCodeLibrary was compiling & deduplicating the shaders. - Remvoe the single linear array for accumulated shader code: reallocating this is tremendously expensive and will double the time taken to iteratively cook large projects. - Uncompress the shader data for the native library system so that it actually works again. - Fix some errant change to the Metal compiler that was trying to wedge the fully compiled library into the single Metal library which is 100% bogus. #jira UE-49192 Change3642919by Chris.Bunner Reverted unintended changes to material static parameter set serialization. Bumped material version to force re-serialization. Fixed a few typos. Change 3642923 by Richard.Wallis Fix for "Pixel Inspector On" message not disappearing when closing pixel inspector window while on. Handle tab closed events to cancel the pixel inspector if window closed while running. #jira UE-46504 Change 3643296 by Michael.Lentine Convert all structures that aren't use globally to halfs. Change 3643381 by Ryan.Brucks New Plugin allowing Blueprint Texture and RT reads as well as MIC creation and modification. Change 3643929 by Ben.Salem Added better precision on thread values in Perf Monitor. Also added global thread values to go with per-world ones to help track down the most accurate numbers possible. #tests Ran locally, changes validated by benj Change 3644203 by Mark.Satterthwaite Refactor mtlpp a little bit to make the compiler do more of the work & update for all the latest publicly exposed APIs. Change 3644336 by Mark.Satterthwaite Ref-count the mtlpp Device object so that it can be the repository for IMP caching - now just have to go through the types created from a specific device and have them keep a reference.... Change 3644431 by Uriel.Doyon Added a intensity units property, for point lights and spot lights, that can be set to Candelas, Lumens or Unitless (legacy). The default units value for newly placed point lights and spot lights is configured in the project settings. Spot lights configured in lumens have their whole luminous energy redirected toward the cone. This means that changing the outer cone angle, changes the spot light brightness. New exposure menu that uses an EV100 slider. New post process settings "camera" tab regrouping : ShutterSpeed, ISO, Aperture and ExposureCompensation. Post process settings "auto exposure" tab renamed "exposure". The calibration constant for "Auto Exposure Basic" is now configurable in the advanced tab. The auto exposure method is renamed "Metering Mode" New pre-exposure feature that allows the engine to apply the previous frame exposure before writing to the scene color. This allows the engine to render the scene with similar range than the final color (after exposure), and avoid arithmetic overflow for low precision RT formats. The amount of exposure applied directly is called pre-exposure, and is compensated by a smaller post-exposure value. Change 3645098 by Marcus.Wassmer Don't add meshes twice when in simpleforward Change 3645551 by Daniel.Wright VolumetricScatteringIntensity is greyed out based on Mobility Change 3645707 by Chris.Bunner Skip empty parameters when identifying invalid duplicates during material translation. Change 3646225 by Uriel.Doyon Texture streaming support for particle sub-uv Change 3646323 by Rolando.Caloca DR - vk - Fix bad update texture 2/3d parameters Change 3646463 by Mark.Satterthwaite Metal shader files that can serve as extensions to the metal_stdlib rather than trying to wedge even more into the shader compiler. Might as well leverage Metal's C++'ness. Currently just a skeleton of a buffer type that would better emulate HLSL Buffer<>/RWBuffer<> objects. Change 3646727 by Marcus.Wassmer fix linux and nonunity compiles Change 3647777 by Rolando.Caloca DR - Mobile Vulkan optimization Change 3647822 by Lauren.Ridge Layers are now renameable (except Layer 0 is always "Background") in Material Layers Functions Change 3647918 by Chris.Bunner Static analysis fixes - Monolithic include, forward delcared enums, locally shadowed variable. Change 3648010 by Michael.Lentine Don't use min16float by default. Change 3648015 by Michael.Lentine Add special case fixes for min16float as well as half on console. Change 3648024 by Lauren.Ridge Moving MaterialLayersFunctions Layer naming to EditorOnly wrappers Change 3648127 by Lauren.Ridge Moving name getter functionality to FMaterialLayersFunctions Change 3648265 by Lauren.Ridge Fixing loctext key Change 3648293 by Rolando.Caloca DR - D3D12 fix Change 3648326 by Rolando.Caloca DR - vk - Added subrectangle support when updating Texture2D and Texture3D Change 3648522 by Rolando.Caloca DR - vk - Do not try to create a BufferView of a StructuredBuffer (no valid pixelformat) Change 3648612 by Rolando.Caloca DR - vk - Implement RHIMapStagingSurface Change 3648673 by Rolando.Caloca DR - vk - Reduce Vulkan pipeline cache disk size by filtering duplicated shader ucodes Change 3648913 by Arne.Schober DR - Performance optimization during HLod traversal. using vector load and avoiding array copy by passing it through reference instead through value. Change 3649443 by Daniel.Wright Exposed EmissiveBoost, since Lightmass supports Emissive areas on meshes Change 3650436 by Mark.Satterthwaite Implemented the necessary extensions for Metal shading language to move lots of complexity out of MetalBackend and into actual shader code to make life *vastly* simpler. - Full ue4::typed_buffer<T> wrapper type & associated ue4::buffer<>/ue4::buffer_atomic<> API - totally untested but should be functionally equivalent to HLSL Buffer<T>/RWBuffer<T>. - All the sensible casts I can think of are now defined in ue4_format - any additional ones can just be added. The enurm of formats needs to be exposed to MetalRHI so we upload the correct values, but this should be trivial. - Added a full series of wrappers around texturecube_array and depthcube_array to insulate code from whether it is backed by a real cube_array or a texture2d_array so we don't have to maintain complicated variants for new/old iOS devices. - Added implementations for a bunch of annoying HLSL & GLSL intrinsics that were being matched by name + reverse_bits which needs a custom implementation on old shader standards. Change 3650861 by Rolando.Caloca DR - vk - Fix warnings Change 3651116 by Rolando.Caloca DR - vk - Support for compressed saved PSO cache Change 3651321 by Rolando.Caloca DR - vk - Prep for load multiple PSO files Change 3651337 by Chris.Bunner Editor-only default material fallback (hardcoded material). #jira UE-48404 Change 3651839 by Rolando.Caloca DR - vk - Integrate minor pipeline changes Change 3652042 by Mark.Satterthwaite More work on mtlpp: - Selector class that caches IMP from SEL & Class. - Fixes to ns::Error. - Added test case application for testing denorm & float reinterpret-cast behaviour on Metal. Change 3652370 by Uriel.Doyon New "stat StreamingOverview" giving high level metrics of texture usage. New function ResetAverageRequiredTexturePoolSize() and GetAverageRequiredTexturePoolSize() giving the average ideal value for "r.streaming.poolsize". Change 3653658 by Chris.Bunner Material vertex interpolator for sprite and gpu sprite particles. Change 3653676 by Rolando.Caloca DR - vk - Integrate changes: Multiple PSO caches, shared ucode & compression, size reduction up to 80% Change 3653940 by Daniel.Wright Moved Volumetric Lightmap textures out of FScene and into FPrecomputedVolumetricLightmapData so their lifetime can match the MapBuildData. This allows tossing the source BulkData in game after RHI texture creation even though switching lighting scenarios does Release/InitializeRenderingResources multiple times. Change 3653956 by Daniel.Wright Fixed leak of BatchVisibilityId's Change 3653991 by Daniel.Wright Fixed missing include Change 3654013 by Daniel.Wright Refactored reflection capture composite SM4 handling, now forces fully rough even if !REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES (forward shading default) Change 3654018 by Daniel.Wright Remove unused SM4 reflection capture cubemap Change 3654118 by Rolando.Caloca DR - vk - Fix for queries; support for r.Vulkan.ProfileCmdBuffers to only time cmd buffers w/o gpu bubbles Change 3654339 by Chris.Bunner Temporarily disabed a material error whilst working with content teams to fix the introduced bugs. Change 3654534 by Daniel.Wright Editor is only supported on Feature Level 5 platforms. Added a message box and exit when SM4 is detected (d3d10, OpenGL 3). Change 3654751 by Rolando.Caloca DR - vk - Add readback for RGB10A2; minor optimization Change 3654940 by Rolando.Caloca DR - vk - Warning fix Change 3655104 by Mark.Satterthwaite Add a bunch of code to mtlpp to wrap the Xcode command-line Metal tools and use them to provide a convenient command-line tool that can compile two Metal shaders & diff the resulting AIR to make debugging easier. Obviously this only works on macOS. Change 3655173 by Jian.Ru Render dithered material as masked if a stencil prepass is not used #jira UE-50064, UE-49537 Change 3655479 by Daniel.Wright Fixed HandleLegacyMapBuildData not getting called on P maps loaded in the editor, which apparently was dropped in an integration error, causing all legacy maps (before the BuildData change) to lose their built lighting. Change 3656341 by Richard.Wallis Metal validation checks to test for drawing of the end of a vertex stream as seen in UE-48172 (Landscape Mesh Flickers Rapidly When Using Sculpting Landscape). This is not a fix for that but just a error log to catch the bad draw calls. #jira UE-48172 Change 3656844 by Rolando.Caloca DR - vk - Avoid microcode copy - Fix link error Change 3656894 by Rolando.Caloca DR - vk - Enable api dump without needing validation enabled Change 3656915 by Marcus.Wassmer Fix DX12 buffer lock for read Change 3657166 by Rolando.Caloca DR - vk - Proper fix for api dump layer Change 3657401 by Rolando.Caloca DR - vk - Linux compile fix Change 3657607 by Rolando.Caloca DR - vk - Prep for changes Change 3658722 by Chris.Bunner Refresh shared texture samplers when changing max ansiotropy level (e.g. scalability settings). #jira UE-30086 Change 3659499 by Daniel.Wright Moved bEnableAutoLODGeneration to LOD category so it's not the only one in HLOD category Change 3659644 by Mark.Satterthwaite D3D11 equivalent to 3656341 (only enabled when -d3ddebug is) to validate DrawIndexedPrimitives isn't trying to draw off the end of the instanced vertex streams which has inconsistent (and potentially undefined) behaviour across the various APIs we support. This fires when painting the landscape because the code attempts to render with a FirstInstance value that is as large as the number of elements in the instance-data streams which D3D11 drivers silently fails to render, but which Metal (& probably Vulkan too) will renders as garbage. This pattern is wrong & will be even more dangerous in a Draw*Indirect world. #jira UE-48172 Change 3659831 by Rolando.Caloca DR - vk - Copy 3657927 (fixes for Mali) Change 3661921 by Rolando.Caloca DR - vk - Minor log/info changes Change 3661985 by Mark.Satterthwaite Change the Metal sampler filter translation to better match D3D. Change 3662050 by Richard.Wallis Compile fix for Metal enums. Change 3662062 by Rolando.Caloca DR - Copy from 3662060 - OpenGL cloth fix Change 3662100 by Mark.Satterthwaite Use a temporary file and an atomic move to put the Metal PCH into the right place and reduce the number of false PCH compile failures on the build farm. Change 3662253 by Daniel.Wright Reflection Captures support Lighting Scenarios without recapturing * Reflection Captures are now part of the Map Build * Modifying a capture in editor will display a preview, but game can only display built captures (black for unbuilt with screen message) * Reflection Capture build data moved to the BuildData package * Building lighting / reflection captures no longer dirties ULevels * Sky lights which capture the scene now work correctly with Lighting Scenarios * Lighting Scenarios must now be loaded for each time they are made visible (no switching back and forth while keeping both loaded) Change 3663215 by Mark.Satterthwaite Initial, incomplete, tool added to mtlpp to help debug macOS Internal Compiler Errors - the mtlpp command-line tool can be fed the debug output from UE4 along with compiler settings to automatically compile shaders and construct the render pipeline that crashes the runtime compiler. So far only macOS render-pipeline-states are supported currently. Change 3663293 by Mark.Satterthwaite Added Metal device selection to the mtlpp command-line tool so I can quickly test compile on dual-GPU Macbook Pro's. Change 3663471 by Daniel.Wright Reflection Capture Builds no longer use UEditorLevelUtils::SetLevelVisibility to control level visibility, which streams out sublevels, modifying nav mesh Fixed status updates during Reflection Capture Build Captures overflowing GMaxNumReflectionCaptures now log a warning instead of pretending that they built successfully Change3664056by Rolando.Caloca DR - Linux compile fix Change 3664460 by Daniel.Wright Restored unused LoadTimesObjectVersion, packages saved with it will issue a warning on load Change 3664802 by Uriel.Doyon Fixed flash created by pre-exposure when the value changed dramatically between frames Change 3664890 by Daniel.Wright Created 'Stat MapBuildData' to track the memory size of lighting and reflection capture build outputs Change 3665163 by Rolando.Caloca DR - Copy from 3665156 - Gracefully fail when there are mem leaks exiting Vulkan Change 3665629 by Daniel.Wright Only Surface domain materials cast shadows in Lightmass Change 3665855 by Marcus.Wassmer PR #4032: Fix comparison of SceneColorFormat (Contributed by Hybrid0) Change 3666707 by Guillaume.Abadie Replaces some custom material node to get View.BufferSizeAndInvSize with ViewProperty material expression in some engine material functions. Change 3667239 by Rolando.Caloca DR - Use hlslcc define for common issues Change 3668108 by Brian.Karis Disabled to Catmull-Rom filter. Too many flickering issues. Disabled antiflicker as well. Change 3668157 by Mark.Satterthwaite In the prototype Metal stdlib extension library add inline versions of the D3D SM6 "wave" intrinsics that can be expressed in terms of Metal 2.0 simd/quad group operations (macOS=simd, iOS=quad). These are unlikely to be as efficient as direct intrinsics but they should be functionally equivalent. These functions are not available *yet* as I still need to hook the ue4_stdlib into MetalShaderFormat & MetalRHI. The following HLSL 6 functions are implemented: WaveAllBitAnd WaveAllMax WaveAllMin WaveAllBitOr WaveAllBitXor WaveAllEqual WaveAllProduct WaveAllSum WaveAllTrue WaveAnyTrue WaveBallot WaveGetLaneCount WaveGetLaneIndex WaveOnce WavePrefixProduct WavePrefixSum WaveReadFirstLane WaveReadLaneAt The following can't be implemented in Metal as of Metal 2.0 AFAIK: WaveGetOrderedIndex WaveIsHelperLane GlobalOrderedCountIncrement QuadReadLaneAt QuadSwapX QuadSwapY Change 3668260 by Olaf.Piesche Cache particle collision shaders regardless of simple forward state Missed this checkin #jira FORT-51307 Change 3669243 by Daniel.Wright Bumped shader version to propagate FReflectionCaptureData rename Change 3669369 by Mark.Satterthwaite Duplicating Metal changes from //UE4/Release-4.18 to Dev-Rendering (//UE4/Dev-Rendering) 3662503 Collapse system-variables to one declaration in MetalUtils to avoid later shader compiler errors when they are specified more than once, which is seemingly permissable. Fixes volumetric fog. #jira UE-50293 3665210 - Invalidate all Metal shaders again to force a recompile to workaround another driver bug. - On macOS compact the clip-distance value into a single output to avoid bugs in the runtime pipeline compilers. - In SCW's direct-compile mode MetalShaderForamt should always dump the resulting Metal shader and print any errors we encounter to the log. - Change FGenerateMetalVisitor to take a FMetalCodeBackend& not a FMetalCodeBackend* to avoid a lot of pointless pointer validation. #jira UE-50244 3665429 Fix a crash on shutdown due to MetalRHI caching vertex-declarations beyond the lifetime of the RHI by moving the cache into the FMetalDynamicRHI itself. #jira UE-50356 3665613 Fix DistanceField rendering on Metal & the associated validation layer error when it is enabled - MetalRHI can't use the same approach as Vulkan without a bit more work. #jira UE-50364 3667584 Fix black flickering on some materials that use World Position Offset - the Metal sincos intrinsic comes into two flavours for single precision floats and we want the precise version not the fast version. The "cross" implementation needed a few more fma's too and this change has to invalidate Metal shaders again to take effect. #jira UE-50399 3667805 Changing sincos in Metal fragment shaders had undesirable side-effects - the compiler is now re-associating another floating point operation - so limit the use of precise::sincos to vertex-shaders for now. This fixes the WPO materials without causing any other obvious problems. #jira UE-50399 Change 3669912 by Mark.Satterthwaite Fix Metal compilation for PCSS shadows - the HLSL that is compiled uses both SampleCmp and Sample which GLSL disallows (shadowSampler types in GLSL only allow SampleCmp) but is perfectly valid in Metal where only the texture type declaration changes. Duplicate MetalBackend.cpp changes from Joe.Graf's: 3667781 Fixed an extra ) being emitted during HLSL->Metal translation Added depthcube_array support per Mark's instructions Change 3670308 by Mark.Satterthwaite Missing autorelease pool blocks in MetalTexture functions. Change 3670989 by Mark.Satterthwaite Stop trying to be so clever with Metal clip-distances: AMD have a bug in 10.13.0 that means we can only emit one clip-distance value, so simply emit the value with the lowest index (we have handily ordered them by importance!) and let the others become user-interpolators until this bug is resolved in a macOS SU (according to Max@AMD the fix is in, just not in time for 4.18). This means planar reflections will work, VR no-multi-view-fallback will work & layered rendering will work either individually or together - the difference being that on macOS *only* the VR no-multi-view-fallback & layered rendering paths may be slower when combined with the global clip plane. Hit & run fix to MetalCaptureManager and availability of tile-shader functions while I'm here. #jira UE-50518 Change 3671014 by Mark.Satterthwaite Correct handling of RowLinearPVRTC blits for iOS Metal desired for Ocean. Change 3671575 by Rolando.Caloca DR - Copy 3668036 Stop syncing CPU with GPU on Vulkan Change 3671637 by Rolando.Caloca DR - Copy3670937Fixes Vulkan editor outline Change 3672309 by Mark.Satterthwaite Submitted on behalf of Richard Wallis: Only disable V-Sync on Metal in macOS 10.13 when running in "true" fullscreen mode (where we switch display modes & forbid switching spaces or tabbing out) so that you won't see the rainbow artefact caused by being out-of-sync with WindowServer, only the tearing you'd expect when V-Sync is disabled. We'll chat with Apple about whether there is a way to avoid the rainbow artefact when switching spaces in Windowed Fullscreen with displaySync disabled. #jira UE-50134 Change 3672314 by Daniel.Wright User friendly message dialog for when a required key is missing from BaseLightmass.ini Change 3672315 by Daniel.Wright Assert on load when a uniform buffer struct goes missing, instead of a crash on save Change 3672476 by Chris.Bunner Removed duplicate material instance editor command binding that appeared in a task stream merge. Change 3672626 by Mark.Satterthwaite Move the ue4_stdlib.metal extensions to MetalRHI's Public header directory as it'll need to be available to both modules and that's easier to accomplish from here. Change 3672643 by Mark.Satterthwaite iOS compilation fixes. Change 3672728 by Daniel.Wright Fixed encoded HDR reflection captures Change 3672753 by Jian.Ru Fix texture swimming #jira UE-49369 Change 3672815 by Daniel.Wright Tooltip for build button explaining why it might be disabled Change 3673350 by Rolando.Caloca DR - vk - Do not reallocate memory every draw call Change 3673501 by Rolando.Caloca DR - vk - Remove more reallocations Change 3673505 by Rolando.Caloca DR - Remove global variable with semantic Change 3673514 by Rolando.Caloca DR - vk - compile fix Change 3675899 by Chris.Bunner Fixed support for editor-time transient parameter overrides. This happens when a compiled material's scalar or vector parameter is changed in value only, the active material resources should also update and be reverted when the material graph is closed. The code was incorrectly pulling base parameters from expressions instead of the actual uniform. Change 3676843 by Arne.Schober DR - UE-49473 - Fix Stateleak caused by custom drawer in the long for loop, where the depth stencil state might not be reset in a subsequent itteration of the loop. Change 3678269 by Daniel.Wright Fixed Encoded HDR reflection capture data getting the wrong Brightness applied when cooking Change 3678543 by Daniel.Wright MapBuildData now tosses the unneeded reflection capture format on load. Affects target platforms that require multiple formats at cook time. Change 3679602 by Jian.Ru Fix up mesh decal shader complexity view mode #jira UE-50272 Change 3679959 by Chris.Bunner Fixed logic on overriden vector parameter retrieval for material instances checking a function owned parameter. #jira UE-50712 Change 3679998 by Daniel.Wright Fixed crash when precomputing static visibility only [CL3680175by Marcus Wassmer in Main branch]
3275 lines
135 KiB
C++
3275 lines
135 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LevelEditorActions.h"
|
|
#include "SceneView.h"
|
|
#include "Factories/Factory.h"
|
|
#include "Animation/AnimSequence.h"
|
|
#include "Components/LightComponent.h"
|
|
#include "HAL/PlatformFilemanager.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/App.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Layout/WidgetPath.h"
|
|
#include "Framework/Application/MenuStack.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "TexAlignTools.h"
|
|
#include "Components/SkeletalMeshComponent.h"
|
|
#include "Materials/Material.h"
|
|
#include "Editor/EditorPerProjectUserSettings.h"
|
|
#include "ISourceControlModule.h"
|
|
#include "Editor/UnrealEdEngine.h"
|
|
#include "Settings/EditorExperimentalSettings.h"
|
|
#include "Factories/BlueprintFactory.h"
|
|
#include "Editor/GroupActor.h"
|
|
#include "Materials/MaterialInstance.h"
|
|
#include "Engine/Light.h"
|
|
#include "Engine/BlueprintGeneratedClass.h"
|
|
#include "Kismet2/ComponentEditorUtils.h"
|
|
#include "Engine/Selection.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "UObject/UObjectIterator.h"
|
|
#include "EngineUtils.h"
|
|
#include "EditorModes.h"
|
|
#include "UnrealEdMisc.h"
|
|
#include "FileHelpers.h"
|
|
#include "EditorModeInterpolation.h"
|
|
#include "UnrealEdGlobals.h"
|
|
#include "Toolkits/AssetEditorManager.h"
|
|
#include "LevelEditor.h"
|
|
#include "Matinee/MatineeActor.h"
|
|
#include "Engine/LevelScriptBlueprint.h"
|
|
#include "LightingBuildOptions.h"
|
|
#include "EditorSupportDelegates.h"
|
|
#include "SLevelEditor.h"
|
|
#include "EditorBuildUtils.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "Kismet2/KismetEditorUtilities.h"
|
|
#include "IContentBrowserSingleton.h"
|
|
#include "ContentBrowserModule.h"
|
|
#include "Interfaces/IMainFrameModule.h"
|
|
#include "DlgDeltaTransform.h"
|
|
#include "Editor/NewLevelDialog/Public/NewLevelDialogModule.h"
|
|
#include "MRUFavoritesList.h"
|
|
#include "Private/SSocketChooser.h"
|
|
#include "SnappingUtils.h"
|
|
#include "LevelEditorViewport.h"
|
|
#include "Layers/ILayers.h"
|
|
#include "IPlacementMode.h"
|
|
#include "IPlacementModeModule.h"
|
|
#include "AssetSelection.h"
|
|
#include "IDocumentation.h"
|
|
#include "SourceCodeNavigation.h"
|
|
#include "EngineAnalytics.h"
|
|
#include "Interfaces/IAnalyticsProvider.h"
|
|
#include "ReferenceViewer.h"
|
|
#include "ISizeMapModule.h"
|
|
#include "EditorClassUtils.h"
|
|
|
|
#include "EditorActorFolders.h"
|
|
#include "ActorPickerMode.h"
|
|
#include "Misc/EngineBuildSettings.h"
|
|
#include "Misc/HotReloadInterface.h"
|
|
#include "SourceControlWindows.h"
|
|
#include "Framework/Notifications/NotificationManager.h"
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
#include "CreateBlueprintFromActorDialog.h"
|
|
#include "Settings/EditorProjectSettings.h"
|
|
#include "Engine/LODActor.h"
|
|
#include "IHierarchicalLODUtilities.h"
|
|
#include "HierarchicalLODUtilitiesModule.h"
|
|
#include "Application/IPortalApplicationWindow.h"
|
|
#include "IPortalServiceLocator.h"
|
|
#include "MaterialShaderQualitySettings.h"
|
|
#include "IVREditorModule.h"
|
|
#include "ComponentRecreateRenderStateContext.h"
|
|
#include "ILauncherPlatform.h"
|
|
#include "LauncherPlatformModule.h"
|
|
#include "Engine/LevelStreaming.h"
|
|
#include "Engine/LevelStreamingKismet.h"
|
|
#include "EditorLevelUtils.h"
|
|
#include "ActorGroupingUtils.h"
|
|
#include "LevelUtils.h"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LevelEditorActions, Log, All);
|
|
|
|
#define LOCTEXT_NAMESPACE "LevelEditorActions"
|
|
|
|
const FName HotReloadModule("HotReload");
|
|
|
|
namespace LevelEditorActionsHelpers
|
|
{
|
|
/**
|
|
* If the passed in class is generated by a Blueprint, it will open that Blueprint, otherwise it will help the user create a Blueprint based on that class
|
|
*
|
|
* @param InWindowTitle The window title if the Blueprint needs to be created
|
|
* @param InBlueprintClass The class to create a Blueprint based on or to open if it is a Blueprint
|
|
* @param InLevelEditor When opening the Blueprint, this level editor is the parent window
|
|
* @param InNewBPName If we have to create a new BP, this is the suggested name
|
|
*/
|
|
UBlueprint* OpenOrCreateBlueprintFromClass(FText InWindowTitle, UClass* InBlueprintClass, TWeakPtr< SLevelEditor > InLevelEditor, FString InNewBPName = TEXT(""))
|
|
{
|
|
UBlueprint* Blueprint = NULL;
|
|
|
|
// If the current set class is not a Blueprint, we need to allow the user to create one to edit
|
|
if(!InBlueprintClass->ClassGeneratedBy)
|
|
{
|
|
Blueprint = FKismetEditorUtilities::CreateBlueprintFromClass(InWindowTitle, InBlueprintClass, InNewBPName);
|
|
}
|
|
else
|
|
{
|
|
Blueprint = Cast<UBlueprint>(InBlueprintClass->ClassGeneratedBy);
|
|
}
|
|
|
|
if(Blueprint)
|
|
{
|
|
// @todo Re-enable once world centric works
|
|
const bool bOpenWorldCentric = false;
|
|
FAssetEditorManager::Get().OpenEditorForAsset(
|
|
Blueprint,
|
|
bOpenWorldCentric ? EToolkitMode::WorldCentric : EToolkitMode::Standalone,
|
|
InLevelEditor.Pin() );
|
|
}
|
|
|
|
return Blueprint;
|
|
}
|
|
|
|
/** Check to see whether this world is a persistent world with a valid file on disk */
|
|
bool IsPersistentWorld(UWorld* InWorld)
|
|
{
|
|
UPackage* Pkg = InWorld ? InWorld->GetOutermost() : nullptr;
|
|
if (Pkg && FPackageName::IsValidLongPackageName(Pkg->GetName()))
|
|
{
|
|
FString FileName;
|
|
return FPackageName::DoesPackageExist(Pkg->GetName(), nullptr, &FileName);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::DefaultCanExecuteAction()
|
|
{
|
|
return FSlateApplication::Get().IsNormalExecution();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BrowseDocumentation()
|
|
{
|
|
IDocumentation::Get()->OpenHome(FDocumentationSourceInfo(TEXT("help_menu")));
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BrowseAPIReference()
|
|
{
|
|
IDocumentation::Get()->OpenAPIHome(FDocumentationSourceInfo(TEXT("help_menu")));
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BrowseCVars()
|
|
{
|
|
GEditor->Exec(GetWorld(), TEXT("help"));
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BrowseViewportControls()
|
|
{
|
|
FString URL;
|
|
if (FUnrealEdMisc::Get().GetURL(TEXT("ViewportControlsURL"), URL))
|
|
{
|
|
FPlatformProcess::LaunchURL(*URL, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::NewLevel()
|
|
{
|
|
if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning())
|
|
{
|
|
return;
|
|
}
|
|
|
|
IMainFrameModule& MainFrameModule = FModuleManager::GetModuleChecked<IMainFrameModule>("MainFrame");
|
|
|
|
FString TemplateMapPackageName;
|
|
FNewLevelDialogModule& NewLevelDialogModule = FModuleManager::LoadModuleChecked<FNewLevelDialogModule>("NewLevelDialog");
|
|
if (NewLevelDialogModule.CreateAndShowNewLevelDialog(MainFrameModule.GetParentWindow(), TemplateMapPackageName))
|
|
{
|
|
// The new map screen will return a blank TemplateName if the user has selected to begin a new blank map
|
|
if (TemplateMapPackageName.IsEmpty())
|
|
{
|
|
GEditor->CreateNewMapForEditing();
|
|
}
|
|
else
|
|
{
|
|
// New map screen returned a non-empty TemplateName, so the user has selected to begin from a template map
|
|
bool TemplateFound = false;
|
|
|
|
// Search all template map folders for a match with TemplateName
|
|
const bool bIncludeReadOnlyRoots = true;
|
|
if ( FPackageName::IsValidLongPackageName(TemplateMapPackageName, bIncludeReadOnlyRoots) )
|
|
{
|
|
const FString MapPackageFilename = FPackageName::LongPackageNameToFilename(TemplateMapPackageName, FPackageName::GetMapPackageExtension());
|
|
if ( FPaths::FileExists(MapPackageFilename) )
|
|
{
|
|
// File found because the size check came back non-zero
|
|
TemplateFound = true;
|
|
|
|
// If there are any unsaved changes to the current level, see if the user wants to save those first.
|
|
bool bPromptUserToSave = true;
|
|
bool bSaveMapPackages = true;
|
|
bool bSaveContentPackages = false;
|
|
if ( FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages) )
|
|
{
|
|
// Load the template map file - passes LoadAsTemplate==true making the
|
|
// level load into an untitled package that won't save over the template
|
|
FEditorFileUtils::LoadMap(*MapPackageFilename, /*bLoadAsTemplate=*/true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!TemplateFound)
|
|
{
|
|
UE_LOG( LevelEditorActions, Warning, TEXT("Couldn't find template map package %s"), *TemplateMapPackageName);
|
|
GEditor->CreateNewMapForEditing();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::NewLevel_CanExecute()
|
|
{
|
|
return FSlateApplication::Get().IsNormalExecution() && !GLevelEditorModeTools().IsTracking();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenLevel()
|
|
{
|
|
FEditorFileUtils::LoadMap();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OpenLevel_CanExecute()
|
|
{
|
|
return FSlateApplication::Get().IsNormalExecution() && !GLevelEditorModeTools().IsTracking();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::DeltaTransform()
|
|
{
|
|
if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning())
|
|
{
|
|
return;
|
|
}
|
|
|
|
FDlgDeltaTransform DeltaDialog;
|
|
|
|
const FDlgDeltaTransform::EResult MoveDialogResult = DeltaDialog.ShowModal();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenRecentFile( int32 RecentFileIndex )
|
|
{
|
|
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( "MainFrame" );
|
|
FMainMRUFavoritesList* RecentsAndFavorites = MainFrameModule.GetMRUFavoritesList();
|
|
|
|
// Save the name of the file we are attempting to load as VerifyFile/AskSaveChanges might rearrange the MRU list on us
|
|
const FString NewPackageName = RecentsAndFavorites->GetMRUItem( RecentFileIndex );
|
|
|
|
if( RecentsAndFavorites->VerifyMRUFile( RecentFileIndex ) )
|
|
{
|
|
// Prompt the user to save any outstanding changes.
|
|
if( FEditorFileUtils::SaveDirtyPackages(true, true, false) )
|
|
{
|
|
FString NewFilename;
|
|
if (FPackageName::TryConvertLongPackageNameToFilename(NewPackageName, NewFilename, FPackageName::GetMapPackageExtension()))
|
|
{
|
|
// Load the requested level.
|
|
FEditorFileUtils::LoadMap(NewFilename);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::OpenFavoriteFile( int32 FavoriteFileIndex )
|
|
{
|
|
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( "MainFrame" );
|
|
FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList();
|
|
|
|
const FString PackageName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex );
|
|
|
|
if( MRUFavoritesList->VerifyFavoritesFile( FavoriteFileIndex ) )
|
|
{
|
|
// Prompt the user to save any outstanding changes
|
|
if( FEditorFileUtils::SaveDirtyPackages(true, true, false) )
|
|
{
|
|
FString FileName;
|
|
if (FPackageName::TryConvertLongPackageNameToFilename(PackageName, FileName, FPackageName::GetMapPackageExtension()))
|
|
{
|
|
// Load the requested level.
|
|
FEditorFileUtils::LoadMap(FileName);
|
|
}
|
|
|
|
// Move the item to the head of the list
|
|
MRUFavoritesList->MoveFavoritesItemToHead(PackageName);
|
|
}
|
|
else
|
|
{
|
|
// something went wrong or the user pressed cancel. Return to the editor so the user doesn't lose their changes
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ToggleFavorite()
|
|
{
|
|
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( "MainFrame" );
|
|
FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList();
|
|
check( MRUFavoritesList );
|
|
|
|
if (LevelEditorActionsHelpers::IsPersistentWorld(GetWorld()))
|
|
{
|
|
const FString PackageName = GetWorld()->GetOutermost()->GetName();
|
|
|
|
// If the map was already favorited, remove it from the favorites
|
|
if ( MRUFavoritesList->ContainsFavoritesItem(PackageName) )
|
|
{
|
|
MRUFavoritesList->RemoveFavoritesItem(PackageName);
|
|
}
|
|
// If the map was not already favorited, add it to the favorites
|
|
else
|
|
{
|
|
MRUFavoritesList->AddFavoritesItem(PackageName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::RemoveFavorite( int32 FavoriteFileIndex )
|
|
{
|
|
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( "MainFrame" );
|
|
FMainMRUFavoritesList* MRUFavoritesList = MainFrameModule.GetMRUFavoritesList();
|
|
|
|
const FString PackageName = MRUFavoritesList->GetFavoritesItem( FavoriteFileIndex );
|
|
|
|
if( MRUFavoritesList->VerifyFavoritesFile( FavoriteFileIndex ) )
|
|
{
|
|
if ( MRUFavoritesList->ContainsFavoritesItem(PackageName) )
|
|
{
|
|
MRUFavoritesList->RemoveFavoritesItem(PackageName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::ToggleFavorite_CanExecute()
|
|
{
|
|
const FMainMRUFavoritesList& MRUFavorites = *FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame").GetMRUFavoritesList();
|
|
const int32 NumFavorites = MRUFavorites.GetNumFavorites();
|
|
// Disable the favorites button if the map isn't associated to a file yet (new map, never before saved, etc.)
|
|
return LevelEditorActionsHelpers::IsPersistentWorld(GetWorld()) && NumFavorites <= FLevelEditorCommands::Get().OpenFavoriteFileCommands.Num();
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::ToggleFavorite_IsChecked()
|
|
{
|
|
bool bIsChecked = false;
|
|
|
|
if (LevelEditorActionsHelpers::IsPersistentWorld(GetWorld()))
|
|
{
|
|
const FString PackageName = GetWorld()->GetOutermost()->GetName();
|
|
|
|
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>( "MainFrame" );
|
|
bIsChecked = MainFrameModule.GetMRUFavoritesList()->ContainsFavoritesItem(PackageName);
|
|
}
|
|
|
|
return bIsChecked;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSaveWorld()
|
|
{
|
|
return FSlateApplication::Get().IsNormalExecution() && (!GUnrealEd || !GUnrealEd->GetPackageAutoSaver().IsAutoSaving());
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::Save()
|
|
{
|
|
FEditorFileUtils::SaveCurrentLevel();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SaveCurrentAs()
|
|
{
|
|
UWorld* World = GetWorld();
|
|
ULevel* CurrentLevel = World->GetCurrentLevel();
|
|
|
|
UClass* CurrentStreamingLevelClass = ULevelStreamingKismet::StaticClass();
|
|
|
|
for (ULevelStreaming* StreamingLevel : World->StreamingLevels)
|
|
{
|
|
if (StreamingLevel->GetLoadedLevel() == CurrentLevel)
|
|
{
|
|
CurrentStreamingLevelClass = StreamingLevel->GetClass();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
const bool bSavedPersistentLevelAs = CurrentLevel == World->PersistentLevel;
|
|
FString SavedFilename;
|
|
bool bSaved = FEditorFileUtils::SaveLevelAs(CurrentLevel, &SavedFilename);
|
|
if(bSaved)
|
|
{
|
|
if (bSavedPersistentLevelAs)
|
|
{
|
|
FEditorFileUtils::LoadMap(SavedFilename);
|
|
}
|
|
else
|
|
{
|
|
// Remove the level we just saved over
|
|
EditorLevelUtils::RemoveLevelFromWorld(CurrentLevel);
|
|
|
|
// Add the new level we just saved as to the plevel
|
|
FString PackageName;
|
|
if (FPackageName::TryConvertFilenameToLongPackageName(SavedFilename, PackageName))
|
|
{
|
|
ULevelStreaming* StreamingLevel = UEditorLevelUtils::AddLevelToWorld(World, *PackageName, CurrentStreamingLevelClass);
|
|
|
|
// Make the level we just added current because the expectation is that the new level replaces the existing current level
|
|
EditorLevelUtils::MakeLevelCurrent(StreamingLevel->GetLoadedLevel());
|
|
}
|
|
|
|
FEditorDelegates::RefreshLevelBrowser.Broadcast();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SaveAllLevels()
|
|
{
|
|
const bool bPromptUserToSave = false;
|
|
const bool bSaveMapPackages = true;
|
|
const bool bSaveContentPackages = false;
|
|
const bool bFastSave = false;
|
|
FEditorFileUtils::SaveDirtyPackages( bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave );
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ImportScene_Clicked()
|
|
{
|
|
FEditorFileUtils::Import();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ExportAll_Clicked()
|
|
{
|
|
const bool bExportSelectedActorsOnly = false;
|
|
FEditorFileUtils::Export( bExportSelectedActorsOnly );
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ExportSelected_Clicked()
|
|
{
|
|
const bool bExportSelectedActorsOnly = true;
|
|
FEditorFileUtils::Export( bExportSelectedActorsOnly );
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::ExportSelected_CanExecute()
|
|
{
|
|
// Only enable the option if at least one thing is selected and its not a worldsettings
|
|
return GEditor->GetSelectedActors()->Num() > 0 && !GEditor->IsWorldSettingsSelected();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AttachToActor(AActor* ParentActorPtr)
|
|
{
|
|
USceneComponent* ComponentWithSockets = NULL;
|
|
|
|
//@TODO: Should create a menu for each component that contains sockets, or have some form of disambiguation within the menu (like a fully qualified path)
|
|
// Instead, we currently only display the sockets on the root component
|
|
if (ParentActorPtr != NULL)
|
|
{
|
|
if (USceneComponent* RootComponent = ParentActorPtr->GetRootComponent())
|
|
{
|
|
if (RootComponent->HasAnySockets())
|
|
{
|
|
ComponentWithSockets = RootComponent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show socket chooser if we have sockets to select
|
|
if (ComponentWithSockets != NULL)
|
|
{
|
|
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( "LevelEditor");
|
|
TSharedPtr< ILevelEditor > LevelEditor = LevelEditorModule.GetFirstLevelEditor();
|
|
|
|
// Create as context menu
|
|
FSlateApplication::Get().PushMenu(
|
|
LevelEditor.ToSharedRef(),
|
|
FWidgetPath(),
|
|
SNew(SSocketChooserPopup)
|
|
.SceneComponent( ComponentWithSockets )
|
|
.OnSocketChosen_Static( &FLevelEditorActionCallbacks::AttachToSocketSelection, ParentActorPtr ),
|
|
FSlateApplication::Get().GetCursorPos(),
|
|
FPopupTransitionEffect( FPopupTransitionEffect::ContextMenu )
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AttachToSocketSelection( NAME_None, ParentActorPtr );
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AttachToSocketSelection(const FName SocketName, AActor* ParentActorPtr)
|
|
{
|
|
FSlateApplication::Get().DismissAllMenus();
|
|
|
|
if(ParentActorPtr != NULL)
|
|
{
|
|
// Attach each child
|
|
FScopedTransaction Transaction(LOCTEXT("AttachActors", "Attach actors"));
|
|
bool bAttached = false;
|
|
|
|
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
|
|
{
|
|
AActor* Actor = Cast<AActor>( *It );
|
|
if (GEditor->CanParentActors(ParentActorPtr, Actor))
|
|
{
|
|
bAttached = true;
|
|
GEditor->ParentActors(ParentActorPtr, Actor, SocketName);
|
|
}
|
|
}
|
|
|
|
if (!bAttached)
|
|
{
|
|
Transaction.Cancel();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetMaterialQualityLevel( EMaterialQualityLevel::Type NewQualityLevel )
|
|
{
|
|
auto* Settings = GetMutableDefault<UEditorPerProjectUserSettings>();
|
|
Settings->MaterialQualityLevel = NewQualityLevel;
|
|
Settings->PostEditChange();
|
|
|
|
//Ensure the material quality cvar is also set.
|
|
static IConsoleVariable* MaterialQualityLevelVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.MaterialQualityLevel"));
|
|
MaterialQualityLevelVar->Set(NewQualityLevel, ECVF_SetByScalability);
|
|
|
|
GUnrealEd->RedrawAllViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsMaterialQualityLevelChecked( EMaterialQualityLevel::Type TestQualityLevel )
|
|
{
|
|
static const auto MaterialQualityLevelVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MaterialQualityLevel"));
|
|
EMaterialQualityLevel::Type MaterialQualityLevel = (EMaterialQualityLevel::Type)FMath::Clamp(MaterialQualityLevelVar->GetValueOnGameThread(), 0, (int32)EMaterialQualityLevel::Num-1);
|
|
return TestQualityLevel == MaterialQualityLevel;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetPreviewPlatform(FName MaterialQualityPlatform, ERHIFeatureLevel::Type PreviewFeatureLevel)
|
|
{
|
|
// If we have specified a MaterialQualityPlatform ensure its feature level matches the requested feature level.
|
|
check(MaterialQualityPlatform.IsNone() || GetMaxSupportedFeatureLevel(ShaderFormatToLegacyShaderPlatform(MaterialQualityPlatform)) == PreviewFeatureLevel);
|
|
|
|
UMaterialShaderQualitySettings* MaterialShaderQualitySettings = UMaterialShaderQualitySettings::Get();
|
|
const FName InitialPreviewPlatform = MaterialShaderQualitySettings->GetPreviewPlatform();
|
|
|
|
const ERHIFeatureLevel::Type InitialFeatureLevel = GetWorld()->FeatureLevel;
|
|
MaterialShaderQualitySettings->SetPreviewPlatform(MaterialQualityPlatform);
|
|
SetFeatureLevelPreview(PreviewFeatureLevel);
|
|
|
|
if (
|
|
// Rebuild materials if the preview platform has changed.
|
|
InitialPreviewPlatform != MaterialQualityPlatform
|
|
// If the feature level changed then materials have been rebuilt already.
|
|
&& InitialFeatureLevel == PreviewFeatureLevel)
|
|
{
|
|
FGlobalComponentRecreateRenderStateContext Recreate;
|
|
FlushRenderingCommands();
|
|
UMaterial::AllMaterialsCacheResourceShadersForRendering();
|
|
UMaterialInstance::AllMaterialsCacheResourceShadersForRendering();
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsPreviewPlatformChecked(FName MaterialQualityPlatform, ERHIFeatureLevel::Type PreviewFeatureLevel)
|
|
{
|
|
const FName& PreviewPlatform = UMaterialShaderQualitySettings::Get()->GetPreviewPlatform();
|
|
return PreviewPlatform == MaterialQualityPlatform && PreviewFeatureLevel == GetWorld()->FeatureLevel;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetFeatureLevelPreview(ERHIFeatureLevel::Type InPreviewFeatureLevel)
|
|
{
|
|
// Record this feature level as we want to use it for all subsequent level creation and loading
|
|
GEditor->DefaultWorldFeatureLevel = InPreviewFeatureLevel;
|
|
|
|
GetWorld()->ChangeFeatureLevel(InPreviewFeatureLevel);
|
|
|
|
// Update any currently running PIE sessions.
|
|
for (TObjectIterator<UWorld> It; It; ++It)
|
|
{
|
|
UWorld* ItWorld = *It;
|
|
if (ItWorld->WorldType == EWorldType::PIE)
|
|
{
|
|
ItWorld->ChangeFeatureLevel(InPreviewFeatureLevel);
|
|
}
|
|
}
|
|
|
|
GUnrealEd->RedrawAllViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsFeatureLevelPreviewChecked(ERHIFeatureLevel::Type InPreviewFeatureLevel)
|
|
{
|
|
return InPreviewFeatureLevel == GetWorld()->FeatureLevel;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ConfigureLightingBuildOptions( const FLightingBuildOptions& Options )
|
|
{
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildSelected"), Options.bOnlyBuildSelected, GEditorPerProjectIni );
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildCurrentLevel"), Options.bOnlyBuildCurrentLevel, GEditorPerProjectIni );
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildSelectedLevels"),Options.bOnlyBuildSelectedLevels, GEditorPerProjectIni );
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("OnlyBuildVisibility"), Options.bOnlyBuildVisibility, GEditorPerProjectIni );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanBuildLighting()
|
|
{
|
|
// Building lighting modifies the BuildData package, which the PIE session will also be referencing without getting notified
|
|
return !(GEditor->PlayWorld || GUnrealEd->bIsSimulatingInEditor);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanBuildReflectionCaptures()
|
|
{
|
|
// Building reflection captures modifies the BuildData package, which the PIE session will also be referencing without getting notified
|
|
return !(GEditor->PlayWorld || GUnrealEd->bIsSimulatingInEditor)
|
|
// Build reflection captures requires SM5. Don't allow building when previewing other feature levels.
|
|
&& GetWorld()->FeatureLevel >= ERHIFeatureLevel::SM5;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::Build_Execute()
|
|
{
|
|
// Reset build options
|
|
ConfigureLightingBuildOptions( FLightingBuildOptions() );
|
|
|
|
// Build everything!
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildAll );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Build_CanExecute()
|
|
{
|
|
return CanBuildLighting() && CanBuildReflectionCaptures();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BuildAndSubmitToSourceControl_Execute()
|
|
{
|
|
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") );
|
|
LevelEditorModule.SummonBuildAndSubmit();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::BuildLightingOnly_Execute()
|
|
{
|
|
// Reset build options
|
|
ConfigureLightingBuildOptions( FLightingBuildOptions() );
|
|
|
|
// Build lighting!
|
|
const bool bAllowLightingDialog = false;
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildLighting, bAllowLightingDialog );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::BuildLighting_CanExecute()
|
|
{
|
|
static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
|
|
const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnGameThread() != 0);
|
|
|
|
return bAllowStaticLighting && CanBuildLighting() && CanBuildReflectionCaptures();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BuildReflectionCapturesOnly_Execute()
|
|
{
|
|
GEditor->BuildReflectionCaptures();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::BuildReflectionCapturesOnly_CanExecute()
|
|
{
|
|
return CanBuildReflectionCaptures();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BuildLightingOnly_VisibilityOnly_Execute()
|
|
{
|
|
// Configure build options
|
|
FLightingBuildOptions LightingBuildOptions;
|
|
LightingBuildOptions.bOnlyBuildVisibility = true;
|
|
ConfigureLightingBuildOptions( LightingBuildOptions );
|
|
|
|
// Build lighting!
|
|
const bool bAllowLightingDialog = false;
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildLighting, bAllowLightingDialog );
|
|
|
|
// Reset build options
|
|
ConfigureLightingBuildOptions( FLightingBuildOptions() );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::LightingBuildOptions_UseErrorColoring_IsChecked()
|
|
{
|
|
bool bUseErrorColoring = false;
|
|
GConfig->GetBool(TEXT("LightingBuildOptions"), TEXT("UseErrorColoring"), bUseErrorColoring, GEditorPerProjectIni);
|
|
return bUseErrorColoring;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::LightingBuildOptions_UseErrorColoring_Toggled()
|
|
{
|
|
bool bUseErrorColoring = false;
|
|
GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("UseErrorColoring"), bUseErrorColoring, GEditorPerProjectIni );
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("UseErrorColoring"), !bUseErrorColoring, GEditorPerProjectIni );
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::LightingBuildOptions_ShowLightingStats_IsChecked()
|
|
{
|
|
bool bShowLightingBuildInfo = false;
|
|
GConfig->GetBool(TEXT("LightingBuildOptions"), TEXT("ShowLightingBuildInfo"), bShowLightingBuildInfo, GEditorPerProjectIni);
|
|
return bShowLightingBuildInfo;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::LightingBuildOptions_ShowLightingStats_Toggled()
|
|
{
|
|
bool bShowLightingBuildInfo = false;
|
|
GConfig->GetBool( TEXT("LightingBuildOptions"), TEXT("ShowLightingBuildInfo"), bShowLightingBuildInfo, GEditorPerProjectIni );
|
|
GConfig->SetBool( TEXT("LightingBuildOptions"), TEXT("ShowLightingBuildInfo"), !bShowLightingBuildInfo, GEditorPerProjectIni );
|
|
}
|
|
|
|
|
|
|
|
void FLevelEditorActionCallbacks::BuildGeometryOnly_Execute()
|
|
{
|
|
// Build geometry!
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildVisibleGeometry );
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::BuildGeometryOnly_OnlyCurrentLevel_Execute()
|
|
{
|
|
// Build geometry (current level)!
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildGeometry );
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::BuildPathsOnly_Execute()
|
|
{
|
|
// Build paths!
|
|
FEditorBuildUtils::EditorBuild( GetWorld(), FBuildOptions::BuildAIPaths );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BuildLODsOnly_Execute()
|
|
{
|
|
// Build HLOD
|
|
FEditorBuildUtils::EditorBuild(GetWorld(), FBuildOptions::BuildHierarchicalLOD);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::BuildTextureStreamingOnly_Execute()
|
|
{
|
|
FEditorBuildUtils::EditorBuildTextureStreaming(GetWorld());
|
|
GEngine->DeferredCommands.AddUnique(TEXT("MAP CHECK NOTIFYRESULTS"));
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsLightingQualityChecked( ELightingBuildQuality TestQuality )
|
|
{
|
|
int32 CurrentQualityLevel;
|
|
GConfig->GetInt(TEXT("LightingBuildOptions"), TEXT("QualityLevel"), CurrentQualityLevel, GEditorPerProjectIni);
|
|
return TestQuality == CurrentQualityLevel;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingQuality( ELightingBuildQuality NewQuality )
|
|
{
|
|
GConfig->SetInt(TEXT("LightingBuildOptions"), TEXT("QualityLevel"), (int32)NewQuality, GEditorPerProjectIni);
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingDensityIdeal()
|
|
{
|
|
return ( GEngine->IdealLightMapDensity );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingDensityIdeal( float Value )
|
|
{
|
|
GEngine->IdealLightMapDensity = Value;
|
|
|
|
// We need to make sure that Maximum is always slightly larger than ideal...
|
|
if (GEngine->IdealLightMapDensity >= GEngine->MaxLightMapDensity - 0.01f)
|
|
{
|
|
SetLightingDensityMaximum( GEngine->IdealLightMapDensity + 0.01f );
|
|
}
|
|
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingDensityMaximum()
|
|
{
|
|
return ( GEngine->MaxLightMapDensity );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingDensityMaximum( float Value )
|
|
{
|
|
GEngine->MaxLightMapDensity = Value;
|
|
|
|
// We need to make sure that Maximum is always slightly larger than ideal...
|
|
if (GEngine->MaxLightMapDensity <= GEngine->IdealLightMapDensity + 0.01f)
|
|
{
|
|
GEngine->MaxLightMapDensity = GEngine->IdealLightMapDensity + 0.01f;
|
|
}
|
|
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingDensityColorScale()
|
|
{
|
|
return ( GEngine->RenderLightMapDensityColorScale );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingDensityColorScale( float Value )
|
|
{
|
|
GEngine->RenderLightMapDensityColorScale = Value;
|
|
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingDensityGrayscaleScale()
|
|
{
|
|
return ( GEngine->RenderLightMapDensityGrayscaleScale );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingDensityGrayscaleScale( float Value )
|
|
{
|
|
GEngine->RenderLightMapDensityGrayscaleScale = Value;
|
|
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingDensityRenderGrayscale()
|
|
{
|
|
GEngine->bRenderLightMapDensityGrayscale = !GEngine->bRenderLightMapDensityGrayscale;
|
|
GEngine->SaveConfig();
|
|
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsLightingDensityRenderGrayscaleChecked()
|
|
{
|
|
return GEngine->bRenderLightMapDensityGrayscale;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionStaticMeshes( ECheckBoxState NewCheckedState )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.bStaticMeshes = ( NewCheckedState == ECheckBoxState::Checked );
|
|
}
|
|
|
|
ECheckBoxState FLevelEditorActionCallbacks::IsLightingResolutionStaticMeshesChecked()
|
|
{
|
|
return ( FLightmapResRatioAdjustSettings::Get().bStaticMeshes ? ECheckBoxState::Checked : ECheckBoxState::Unchecked );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionBSPSurfaces( ECheckBoxState NewCheckedState )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.bBSPSurfaces = ( NewCheckedState == ECheckBoxState::Checked );
|
|
}
|
|
|
|
ECheckBoxState FLevelEditorActionCallbacks::IsLightingResolutionBSPSurfacesChecked()
|
|
{
|
|
return ( FLightmapResRatioAdjustSettings::Get().bBSPSurfaces ? ECheckBoxState::Checked : ECheckBoxState::Unchecked );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionLevel( FLightmapResRatioAdjustSettings::AdjustLevels NewLevel )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.LevelOptions = NewLevel;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsLightingResolutionLevelChecked( FLightmapResRatioAdjustSettings::AdjustLevels TestLevel )
|
|
{
|
|
return ( FLightmapResRatioAdjustSettings::Get().LevelOptions == TestLevel );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionSelectedObjectsOnly()
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.bSelectedObjectsOnly = !Settings.bSelectedObjectsOnly;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsLightingResolutionSelectedObjectsOnlyChecked()
|
|
{
|
|
return FLightmapResRatioAdjustSettings::Get().bSelectedObjectsOnly;
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingResolutionMinSMs()
|
|
{
|
|
return static_cast<float>( FLightmapResRatioAdjustSettings::Get().Min_StaticMeshes );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionMinSMs( float Value )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.Min_StaticMeshes = static_cast<int32>( Value );
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingResolutionMaxSMs()
|
|
{
|
|
return static_cast<float>( FLightmapResRatioAdjustSettings::Get().Max_StaticMeshes );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionMaxSMs( float Value )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.Max_StaticMeshes = static_cast<int32>( Value );
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingResolutionMinBSPs()
|
|
{
|
|
return static_cast<float>( FLightmapResRatioAdjustSettings::Get().Min_BSPSurfaces );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionMinBSPs( float Value )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.Min_BSPSurfaces = static_cast<int32>( Value );
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetLightingResolutionMaxBSPs()
|
|
{
|
|
return static_cast<float>( FLightmapResRatioAdjustSettings::Get().Max_BSPSurfaces );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionMaxBSPs( float Value )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
Settings.Max_BSPSurfaces = static_cast<int32>( Value );
|
|
}
|
|
|
|
int32 FLevelEditorActionCallbacks::GetLightingResolutionRatio()
|
|
{
|
|
return FMath::RoundToInt(FLightmapResRatioAdjustSettings::Get().Ratio * 100.0f);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionRatio( int32 Value )
|
|
{
|
|
FLightmapResRatioAdjustSettings& Settings = FLightmapResRatioAdjustSettings::Get();
|
|
const float NewValue = Value / 100.0f;
|
|
if ( Settings.Ratio != NewValue )
|
|
{
|
|
Settings.Ratio = NewValue;
|
|
Settings.ApplyRatioAdjustment();
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetLightingResolutionRatioCommit( int32 Value, ETextCommit::Type CommitInfo)
|
|
{
|
|
if ((CommitInfo == ETextCommit::OnEnter) || (CommitInfo == ETextCommit::OnUserMovedFocus))
|
|
{
|
|
SetLightingResolutionRatio( Value );
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ShowLightingStaticMeshInfo()
|
|
{
|
|
if (GUnrealEd)
|
|
{
|
|
GUnrealEd->ShowLightingStaticMeshInfoWindow();
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ShowSceneStats()
|
|
{
|
|
if (GUnrealEd)
|
|
{
|
|
GUnrealEd->OpenSceneStatsWindow();
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ShowTextureStats()
|
|
{
|
|
if (GUnrealEd)
|
|
{
|
|
GUnrealEd->OpenTextureStatsWindow();
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::MapCheck_Execute()
|
|
{
|
|
GEditor->Exec( GetWorld(), TEXT("MAP CHECK") );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanShowSourceCodeActions()
|
|
{
|
|
if (GEditor)
|
|
{
|
|
// Don't allow hot reloading if we're running networked PIE instances
|
|
// The reason, is it's fairly complicated to handle the re-wiring that needs to happen when we re-instance objects like player controllers, possessed pawns, etc...
|
|
const TIndirectArray<FWorldContext>& WorldContextList = GEditor->GetWorldContexts();
|
|
|
|
for (const FWorldContext& WorldContext : WorldContextList)
|
|
{
|
|
if (WorldContext.World() && WorldContext.World()->WorldType == EWorldType::PIE && WorldContext.World()->NetDriver)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked<IHotReloadInterface>(HotReloadModule);
|
|
// If there is at least one loaded game module, source code actions should be available.
|
|
return HotReloadSupport.IsAnyGameModuleLoaded();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::RecompileGameCode_Clicked()
|
|
{
|
|
// Don't allow a recompile while already compiling!
|
|
IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked<IHotReloadInterface>(HotReloadModule);
|
|
if( !HotReloadSupport.IsCurrentlyCompiling() )
|
|
{
|
|
// Don't wait -- we want compiling to happen asynchronously
|
|
const bool bWaitForCompletion = false;
|
|
HotReloadSupport.DoHotReloadFromEditor(bWaitForCompletion);
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Recompile_CanExecute()
|
|
{
|
|
// We're not able to recompile if a compile is already in progress!
|
|
|
|
IHotReloadInterface& HotReloadSupport = FModuleManager::LoadModuleChecked<IHotReloadInterface>(HotReloadModule);
|
|
return !HotReloadSupport.IsCurrentlyCompiling() && !(FApp::GetEngineIsPromotedBuild() && FEngineBuildSettings::IsPerforceBuild());
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ConnectToSourceControl_Clicked()
|
|
{
|
|
// Show login window regardless of current status - its useful as a shortcut to change settings.
|
|
ISourceControlModule& SourceControlModule = ISourceControlModule::Get();
|
|
SourceControlModule.ShowLoginDialog(FSourceControlLoginClosed(), ELoginWindowMode::Modeless, EOnLoginWindowStartup::PreserveProvider);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CheckOutModifiedFiles_CanExecute()
|
|
{
|
|
ISourceControlModule& SourceControlModule = ISourceControlModule::Get();
|
|
if (ISourceControlModule::Get().IsEnabled() &&
|
|
ISourceControlModule::Get().GetProvider().IsAvailable())
|
|
{
|
|
TArray<UPackage*> PackagesToSave;
|
|
FEditorFileUtils::GetDirtyWorldPackages(PackagesToSave);
|
|
FEditorFileUtils::GetDirtyContentPackages(PackagesToSave);
|
|
|
|
return PackagesToSave.Num() > 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::CheckOutModifiedFiles_Clicked()
|
|
{
|
|
TArray<UPackage*> PackagesToSave;
|
|
FEditorFileUtils::GetDirtyWorldPackages(PackagesToSave);
|
|
FEditorFileUtils::GetDirtyContentPackages(PackagesToSave);
|
|
|
|
const bool bCheckDirty = true;
|
|
const bool bPromptUserToSave = false;
|
|
FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, bCheckDirty, bPromptUserToSave);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::SubmitToSourceControl_CanExecute()
|
|
{
|
|
ISourceControlModule& SourceControlModule = ISourceControlModule::Get();
|
|
return ISourceControlModule::Get().IsEnabled() &&
|
|
ISourceControlModule::Get().GetProvider().IsAvailable() &&
|
|
FSourceControlWindows::CanChoosePackagesToCheckIn();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SubmitToSourceControl_Clicked()
|
|
{
|
|
FSourceControlWindows::ChoosePackagesToCheckIn();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::GoToCodeForActor_Clicked()
|
|
{
|
|
const auto& SelectedActorInfo = AssetSelectionUtils::GetSelectedActorInfo();
|
|
FSourceCodeNavigation::NavigateToClass(SelectedActorInfo.SelectionClass);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::GoToDocsForActor_Clicked()
|
|
{
|
|
const auto& SelectedActorInfo = AssetSelectionUtils::GetSelectedActorInfo();
|
|
if( SelectedActorInfo.SelectionClass != nullptr )
|
|
{
|
|
FString DocumentationLink = FEditorClassUtils::GetDocumentationLink(SelectedActorInfo.SelectionClass);
|
|
if (!DocumentationLink.IsEmpty())
|
|
{
|
|
IDocumentation::Get()->Open( DocumentationLink, FDocumentationSourceInfo(TEXT("rightclick_viewdoc")) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::FindInContentBrowser_Clicked()
|
|
{
|
|
GEditor->SyncToContentBrowser();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ViewReferences_Execute()
|
|
{
|
|
if( GEditor->GetSelectedActorCount() > 0 )
|
|
{
|
|
TArray< UObject* > ReferencedAssets;
|
|
GEditor->GetReferencedAssetsForEditorSelection( ReferencedAssets );
|
|
|
|
if (ReferencedAssets.Num() > 0)
|
|
{
|
|
TArray< FName > ViewableObjects;
|
|
for( auto ObjectIter = ReferencedAssets.CreateConstIterator(); ObjectIter; ++ObjectIter )
|
|
{
|
|
// Don't allow user to perform certain actions on objects that aren't actually assets (e.g. Level Script blueprint objects)
|
|
const auto EditingObject = *ObjectIter;
|
|
if( EditingObject != NULL && EditingObject->IsAsset() )
|
|
{
|
|
ViewableObjects.Add( EditingObject->GetOuter()->GetFName());
|
|
}
|
|
}
|
|
|
|
IReferenceViewerModule::Get().InvokeReferenceViewerTab(ViewableObjects);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanViewReferences()
|
|
{
|
|
TArray< UObject* > ReferencedAssets;
|
|
GEditor->GetReferencedAssetsForEditorSelection(ReferencedAssets);
|
|
return ReferencedAssets.Num() > 0;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ViewSizeMap_Execute()
|
|
{
|
|
if( GEditor->GetSelectedActorCount() > 0 )
|
|
{
|
|
TArray< UObject* > ReferencedAssets;
|
|
GEditor->GetReferencedAssetsForEditorSelection( ReferencedAssets );
|
|
|
|
if (ReferencedAssets.Num() > 0)
|
|
{
|
|
TArray< FName > ViewableObjects;
|
|
for( auto ObjectIter = ReferencedAssets.CreateConstIterator(); ObjectIter; ++ObjectIter )
|
|
{
|
|
// Don't allow user to perform certain actions on objects that aren't actually assets (e.g. Level Script blueprint objects)
|
|
const auto EditingObject = *ObjectIter;
|
|
if( EditingObject != NULL && EditingObject->IsAsset() )
|
|
{
|
|
ViewableObjects.Add( EditingObject->GetOuter()->GetFName());
|
|
}
|
|
}
|
|
|
|
ISizeMapModule::Get().InvokeSizeMapTab(ViewableObjects);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanViewSizeMap()
|
|
{
|
|
TArray< UObject* > ReferencedAssets;
|
|
GEditor->GetReferencedAssetsForEditorSelection(ReferencedAssets);
|
|
return ReferencedAssets.Num() > 0;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::EditAsset_Clicked( const EToolkitMode::Type ToolkitMode, TWeakPtr< SLevelEditor > LevelEditor, bool bConfirmMultiple )
|
|
{
|
|
if( GEditor->GetSelectedActorCount() > 0 )
|
|
{
|
|
TArray< UObject* > ReferencedAssets;
|
|
const bool bIgnoreOtherAssetsIfBPReferenced = true;
|
|
GEditor->GetReferencedAssetsForEditorSelection( ReferencedAssets, bIgnoreOtherAssetsIfBPReferenced );
|
|
|
|
bool bShouldOpenEditors = (ReferencedAssets.Num() == 1);
|
|
|
|
if (ReferencedAssets.Num() > 1)
|
|
{
|
|
if (bConfirmMultiple)
|
|
{
|
|
int32 Response = FMessageDialog::Open(
|
|
EAppMsgType::YesNo,
|
|
LOCTEXT("OpenAllAssetEditors", "There is more than one referenced asset in the selection. Do you want to open them all for editing?")
|
|
);
|
|
|
|
bShouldOpenEditors = (Response == EAppReturnType::Yes);
|
|
}
|
|
else
|
|
{
|
|
bShouldOpenEditors = true;
|
|
}
|
|
}
|
|
|
|
if (bShouldOpenEditors)
|
|
{
|
|
// Clear focus so the level viewport can receive its focus lost call (and clear pending keyup events which wouldn't arrive)
|
|
FSlateApplication::Get().ClearKeyboardFocus(EFocusCause::WindowActivate);
|
|
|
|
auto LevelEditorSharedPtr = LevelEditor.Pin();
|
|
|
|
if (LevelEditorSharedPtr.IsValid())
|
|
{
|
|
for (auto Asset : ReferencedAssets)
|
|
{
|
|
FAssetEditorManager::Get().OpenEditorForAsset(Asset, ToolkitMode, LevelEditorSharedPtr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::LockActorMovement_Clicked()
|
|
{
|
|
GEditor->ToggleSelectedActorMovementLock();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::DetachActor_Clicked()
|
|
{
|
|
GEditor->DetachSelectedActors();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AttachSelectedActors()
|
|
{
|
|
GUnrealEd->AttachSelectedActors();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AttachActorIteractive()
|
|
{
|
|
if(GUnrealEd->GetSelectedActorCount())
|
|
{
|
|
FActorPickerModeModule& ActorPickerMode = FModuleManager::Get().GetModuleChecked<FActorPickerModeModule>("ActorPickerMode");
|
|
|
|
ActorPickerMode.BeginActorPickingMode(
|
|
FOnGetAllowedClasses(),
|
|
FOnShouldFilterActor::CreateStatic(&FLevelEditorActionCallbacks::IsAttachableActor),
|
|
FOnActorSelected::CreateStatic(&FLevelEditorActionCallbacks::AttachToActor)
|
|
);
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsAttachableActor( const AActor* const ParentActor )
|
|
{
|
|
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
|
|
{
|
|
AActor* Actor = static_cast<AActor*>( *It );
|
|
if (!GEditor->CanParentActors(ParentActor, Actor))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
USceneComponent* ChildRoot = Actor->GetRootComponent();
|
|
USceneComponent* ParentRoot = ParentActor->GetRootComponent();
|
|
|
|
if (ChildRoot != nullptr && ParentRoot != nullptr && ChildRoot->IsAttachedTo(ParentRoot))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::CreateNewOutlinerFolder_Clicked()
|
|
{
|
|
const FName NewFolderName = FActorFolders::Get().GetDefaultFolderNameForSelection(*GetWorld());
|
|
FActorFolders::Get().CreateFolderContainingSelection(*GetWorld(), NewFolderName);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::GoHere_Clicked( const FVector* Point )
|
|
{
|
|
if( GCurrentLevelEditingViewportClient )
|
|
{
|
|
FVector ZoomToPoint;
|
|
if( !Point )
|
|
{
|
|
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
|
|
GCurrentLevelEditingViewportClient->Viewport,
|
|
GCurrentLevelEditingViewportClient->GetWorld()->Scene,
|
|
GCurrentLevelEditingViewportClient->EngineShowFlags)
|
|
.SetRealtimeUpdate(true));
|
|
|
|
|
|
FSceneView* SceneView = GCurrentLevelEditingViewportClient->CalcSceneView(&ViewFamily);
|
|
|
|
if(SceneView)
|
|
{
|
|
FIntPoint MousePosition;
|
|
FVector WorldOrigin;
|
|
FVector WorldDirection;
|
|
GCurrentLevelEditingViewportClient->Viewport->GetMousePos(MousePosition);
|
|
|
|
SceneView->DeprojectFVector2D(MousePosition, WorldOrigin, WorldDirection);
|
|
|
|
FHitResult HitResult;
|
|
|
|
FCollisionQueryParams LineParams(SCENE_QUERY_STAT(FocusOnPoint), true);
|
|
|
|
if(GCurrentLevelEditingViewportClient->GetWorld()->LineTraceSingleByObjectType(HitResult, WorldOrigin, WorldOrigin + WorldDirection * HALF_WORLD_MAX, FCollisionObjectQueryParams(ECC_WorldStatic), LineParams))
|
|
{
|
|
ZoomToPoint = HitResult.ImpactPoint;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ZoomToPoint = *Point;
|
|
}
|
|
|
|
const float PushOutSize = 500;
|
|
FBox BoundingBox(ZoomToPoint-PushOutSize, ZoomToPoint+PushOutSize);
|
|
|
|
GCurrentLevelEditingViewportClient->FocusViewportOnBox(BoundingBox);
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::LockActorMovement_IsChecked()
|
|
{
|
|
return GEditor->HasLockedActors();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AddActor_Clicked( UActorFactory* ActorFactory, FAssetData AssetData, bool bUsePlacement )
|
|
{
|
|
UObject* Object = AssetData.GetAsset();
|
|
if(bUsePlacement && IPlacementModeModule::IsAvailable() && Object != NULL)
|
|
{
|
|
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
|
|
LevelEditorModule.FocusViewport();
|
|
|
|
// Make sure we're in actor placement mode
|
|
GLevelEditorModeTools().ActivateMode(FBuiltinEditorModes::EM_Placement);
|
|
|
|
TArray<UObject*> AssetsToPlace;
|
|
AssetsToPlace.Add(Object);
|
|
|
|
auto* PlacementMode = GLevelEditorModeTools().GetActiveModeTyped<IPlacementMode>(FBuiltinEditorModes::EM_Placement);
|
|
PlacementMode->StartPlacing(AssetsToPlace, ActorFactory);
|
|
}
|
|
else
|
|
{
|
|
FLevelEditorActionCallbacks::AddActor(ActorFactory, AssetData, NULL);
|
|
}
|
|
}
|
|
|
|
AActor* FLevelEditorActionCallbacks::AddActor( UActorFactory* ActorFactory, const FAssetData& AssetData, const FTransform* ActorTransform )
|
|
{
|
|
AActor* NewActor = GEditor->UseActorFactory( ActorFactory, AssetData, ActorTransform );
|
|
|
|
if ( NewActor != NULL && IPlacementModeModule::IsAvailable() )
|
|
{
|
|
IPlacementModeModule::Get().AddToRecentlyPlaced( AssetData.GetAsset(), ActorFactory );
|
|
}
|
|
|
|
return NewActor;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AddActorFromClass_Clicked( UClass* ActorClass )
|
|
{
|
|
FLevelEditorActionCallbacks::AddActorFromClass(ActorClass);
|
|
}
|
|
|
|
AActor* FLevelEditorActionCallbacks::AddActorFromClass( UClass* ActorClass )
|
|
{
|
|
AActor* NewActor = NULL;
|
|
|
|
if ( ActorClass )
|
|
{
|
|
// Look for an actor factory capable of creating actors of that type.
|
|
UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass( ActorClass );
|
|
if( ActorFactory )
|
|
{
|
|
NewActor = GEditor->UseActorFactoryOnCurrentSelection( ActorFactory, nullptr );
|
|
|
|
if ( NewActor != NULL && IPlacementModeModule::IsAvailable() )
|
|
{
|
|
IPlacementModeModule::Get().AddToRecentlyPlaced( ActorClass, ActorFactory );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No actor factory was found; use SpawnActor instead.
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("ACTOR ADD CLASS=%s"), *ActorClass->GetName() ) );
|
|
}
|
|
}
|
|
|
|
return NewActor;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ReplaceActors_Clicked( UActorFactory* ActorFactory, FAssetData AssetData )
|
|
{
|
|
FLevelEditorActionCallbacks::ReplaceActors(ActorFactory, AssetData);
|
|
}
|
|
|
|
AActor* FLevelEditorActionCallbacks::ReplaceActors( UActorFactory* ActorFactory, const FAssetData& AssetData )
|
|
{
|
|
AActor* NewActor = NULL;
|
|
|
|
// Have a first stab at filling in the factory properties.
|
|
FText ErrorMessage;
|
|
if( ActorFactory->CanCreateActorFrom( AssetData, ErrorMessage ) )
|
|
{
|
|
// Replace all selected actors with actors created from the specified factory
|
|
GEditor->ReplaceSelectedActors( ActorFactory, AssetData );
|
|
|
|
if ( IPlacementModeModule::IsAvailable() )
|
|
{
|
|
IPlacementModeModule::Get().AddToRecentlyPlaced( AssetData.GetAsset(), ActorFactory );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FNotificationInfo ErrorNotification( ErrorMessage );
|
|
ErrorNotification.Image = FEditorStyle::GetBrush(TEXT("MessageLog.Error"));
|
|
ErrorNotification.bFireAndForget = true;
|
|
ErrorNotification.ExpireDuration = 3.0f; // Need this message to last a little longer than normal since the user may want to "Show Log"
|
|
ErrorNotification.bUseThrobber = true;
|
|
|
|
FSlateNotificationManager::Get().AddNotification(ErrorNotification);
|
|
}
|
|
|
|
return NewActor;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ReplaceActorsFromClass_Clicked( UClass* ActorClass )
|
|
{
|
|
if ( ActorClass )
|
|
{
|
|
// Look for an actor factory capable of creating actors of that type.
|
|
UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass( ActorClass );
|
|
if( ActorFactory )
|
|
{
|
|
// Replace all selected actors with actors created from the specified factory
|
|
UObject* TargetAsset = GEditor->GetSelectedObjects()->GetTop<UObject>();
|
|
|
|
FText ErrorMessage;
|
|
FText UnusedErrorMessage;
|
|
const FAssetData NoAssetData;
|
|
const FAssetData TargetAssetData(TargetAsset);
|
|
if( ActorFactory->CanCreateActorFrom( TargetAssetData, ErrorMessage ) )
|
|
{
|
|
// Replace all selected actors with actors created from the specified factory
|
|
GEditor->ReplaceSelectedActors( ActorFactory, TargetAssetData );
|
|
}
|
|
else if ( ActorFactory->CanCreateActorFrom( NoAssetData, UnusedErrorMessage ) )
|
|
{
|
|
// Replace all selected actors with actors created from the specified factory
|
|
GEditor->ReplaceSelectedActors( ActorFactory, NoAssetData );
|
|
}
|
|
else
|
|
{
|
|
FNotificationInfo ErrorNotification( ErrorMessage );
|
|
ErrorNotification.Image = FEditorStyle::GetBrush(TEXT("MessageLog.Error"));
|
|
ErrorNotification.bFireAndForget = true;
|
|
ErrorNotification.ExpireDuration = 3.0f; // Need this message to last a little longer than normal since the user may want to "Show Log"
|
|
ErrorNotification.bUseThrobber = true;
|
|
|
|
FSlateNotificationManager::Get().AddNotification(ErrorNotification);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No actor factory was found; use SpawnActor instead.
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("ACTOR REPLACE CLASS=%s"), *ActorClass->GetName() ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Duplicate_CanExecute()
|
|
{
|
|
TArray<FEdMode*> ActiveModes;
|
|
GLevelEditorModeTools().GetActiveModes( ActiveModes );
|
|
for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex )
|
|
{
|
|
const EEditAction::Type CanProcess = ActiveModes[ModeIndex]->GetActionEditDuplicate();
|
|
if (CanProcess == EEditAction::Process)
|
|
{
|
|
return true;
|
|
}
|
|
else if (CanProcess == EEditAction::Halt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If we can copy, we can duplicate
|
|
bool bCanCopy = false;
|
|
if (GEditor->GetSelectedComponentCount() > 0)
|
|
{
|
|
TArray<UActorComponent*> SelectedComponents;
|
|
for (FSelectionIterator It(GEditor->GetSelectedComponentIterator()); It; ++It)
|
|
{
|
|
SelectedComponents.Add(CastChecked<UActorComponent>(*It));
|
|
}
|
|
|
|
bCanCopy = FComponentEditorUtils::CanCopyComponents(SelectedComponents);
|
|
}
|
|
else
|
|
{
|
|
bCanCopy = GUnrealEd->CanCopySelectedActorsToClipboard(GetWorld());
|
|
}
|
|
|
|
return bCanCopy;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Delete_CanExecute()
|
|
{
|
|
TArray<FEdMode*> ActiveModes;
|
|
GLevelEditorModeTools().GetActiveModes( ActiveModes );
|
|
for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex )
|
|
{
|
|
const EEditAction::Type CanProcess = ActiveModes[ModeIndex]->GetActionEditDelete();
|
|
if (CanProcess == EEditAction::Process)
|
|
{
|
|
return true;
|
|
}
|
|
else if (CanProcess == EEditAction::Halt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool bCanDelete = false;
|
|
if (GEditor->GetSelectedComponentCount() > 0)
|
|
{
|
|
TArray<UActorComponent*> SelectedComponents;
|
|
for (FSelectionIterator It(GEditor->GetSelectedComponentIterator()); It; ++It)
|
|
{
|
|
SelectedComponents.Add(CastChecked<UActorComponent>(*It));
|
|
}
|
|
|
|
bCanDelete = FComponentEditorUtils::CanDeleteComponents(SelectedComponents);
|
|
}
|
|
else
|
|
{
|
|
bCanDelete = GUnrealEd->CanDeleteSelectedActors(GetWorld(), true, false);
|
|
}
|
|
|
|
return bCanDelete;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::Rename_Execute()
|
|
{
|
|
UActorComponent* Component = Cast<UActorComponent>(*GEditor->GetSelectedComponentIterator());
|
|
if (Component)
|
|
{
|
|
GEditor->BroadcastLevelComponentRequestRename(Component);
|
|
}
|
|
else
|
|
{
|
|
AActor* Actor = Cast<AActor>(*GEditor->GetSelectedActorIterator());
|
|
if (Actor)
|
|
{
|
|
GEditor->BroadcastLevelActorRequestRename(Actor);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Rename_CanExecute()
|
|
{
|
|
bool bCanRename = false;
|
|
if (GEditor->GetSelectedComponentCount() == 1)
|
|
{
|
|
if (UActorComponent* ComponentToRename = GEditor->GetSelectedComponents()->GetTop<UActorComponent>())
|
|
{
|
|
// We can't edit non-instance components or the default scene root
|
|
bCanRename = ComponentToRename->CreationMethod == EComponentCreationMethod::Instance && ComponentToRename->GetFName() != USceneComponent::GetDefaultSceneRootVariableName();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bCanRename = GEditor->GetSelectedActorCount() == 1;
|
|
}
|
|
|
|
return bCanRename;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Cut_CanExecute()
|
|
{
|
|
TArray<FEdMode*> ActiveModes;
|
|
GLevelEditorModeTools().GetActiveModes( ActiveModes );
|
|
for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex )
|
|
{
|
|
const EEditAction::Type CanProcess = ActiveModes[ModeIndex]->GetActionEditCut();
|
|
if (CanProcess == EEditAction::Process)
|
|
{
|
|
return true;
|
|
}
|
|
else if (CanProcess == EEditAction::Halt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool bCanCut = false;
|
|
if (GEditor->GetSelectedComponentCount() > 0)
|
|
{
|
|
// Make sure the components can be copied and deleted
|
|
TArray<UActorComponent*> SelectedComponents;
|
|
for (FSelectionIterator It(GEditor->GetSelectedComponentIterator()); It; ++It)
|
|
{
|
|
SelectedComponents.Add(CastChecked<UActorComponent>(*It));
|
|
}
|
|
|
|
bCanCut = FComponentEditorUtils::CanCopyComponents(SelectedComponents) && FComponentEditorUtils::CanDeleteComponents(SelectedComponents);
|
|
}
|
|
else
|
|
{
|
|
// For actors, if we can copy, we can cut
|
|
bCanCut = GUnrealEd->CanCopySelectedActorsToClipboard(GetWorld());
|
|
}
|
|
|
|
return bCanCut;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Copy_CanExecute()
|
|
{
|
|
TArray<FEdMode*> ActiveModes;
|
|
GLevelEditorModeTools().GetActiveModes( ActiveModes );
|
|
for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex )
|
|
{
|
|
const EEditAction::Type CanProcess = ActiveModes[ModeIndex]->GetActionEditCopy();
|
|
if (CanProcess == EEditAction::Process)
|
|
{
|
|
return true;
|
|
}
|
|
else if (CanProcess == EEditAction::Halt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool bCanCopy = false;
|
|
if (GEditor->GetSelectedComponentCount() > 0)
|
|
{
|
|
TArray<UActorComponent*> SelectedComponents;
|
|
for (FSelectionIterator It(GEditor->GetSelectedComponentIterator()); It; ++It)
|
|
{
|
|
SelectedComponents.Add(CastChecked<UActorComponent>(*It));
|
|
}
|
|
|
|
bCanCopy = FComponentEditorUtils::CanCopyComponents(SelectedComponents);
|
|
}
|
|
else
|
|
{
|
|
bCanCopy = GUnrealEd->CanCopySelectedActorsToClipboard(GetWorld());
|
|
}
|
|
|
|
return bCanCopy;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::Paste_CanExecute()
|
|
{
|
|
TArray<FEdMode*> ActiveModes;
|
|
GLevelEditorModeTools().GetActiveModes( ActiveModes );
|
|
for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex )
|
|
{
|
|
const EEditAction::Type CanProcess = ActiveModes[ModeIndex]->GetActionEditPaste();
|
|
if (CanProcess == EEditAction::Process)
|
|
{
|
|
return true;
|
|
}
|
|
else if (CanProcess == EEditAction::Halt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool bCanPaste = false;
|
|
if (GEditor->GetSelectedComponentCount() > 0)
|
|
{
|
|
if(ensureMsgf(GEditor->GetSelectedActorCount() == 1, TEXT("Expected SelectedActorCount to be 1 but was %d"), GEditor->GetSelectedActorCount()))
|
|
{
|
|
auto SelectedActor = CastChecked<AActor>(*GEditor->GetSelectedActorIterator());
|
|
bCanPaste = FComponentEditorUtils::CanPasteComponents(SelectedActor->GetRootComponent());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bCanPaste = GUnrealEd->CanPasteSelectedActorsFromClipboard(GetWorld());
|
|
}
|
|
|
|
return bCanPaste;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::PasteHere_CanExecute()
|
|
{
|
|
return Paste_CanExecute(); // For now, just do the same check as Paste
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::ExecuteExecCommand( FString Command )
|
|
{
|
|
UWorld* OldWorld = nullptr;
|
|
|
|
// The play world needs to be selected if it exists
|
|
if (GIsEditor && GEditor->PlayWorld && !GIsPlayInEditorWorld)
|
|
{
|
|
OldWorld = SetPlayInEditorWorld(GEditor->PlayWorld);
|
|
}
|
|
|
|
GUnrealEd->Exec(GetWorld(), *Command);
|
|
|
|
// Restore the old world if there was one
|
|
if (OldWorld)
|
|
{
|
|
RestoreEditorWorld(OldWorld);
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectAllActorsOfClass( bool bArchetype )
|
|
{
|
|
GEditor->SelectAllActorsWithClass( bArchetype );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectComponentOwnerActor()
|
|
{
|
|
auto ComponentOwner = Cast<AActor>(*GEditor->GetSelectedActorIterator());
|
|
check(ComponentOwner);
|
|
|
|
GEditor->SelectNone(true, true, false);
|
|
GEditor->SelectActor(ComponentOwner, true, true, true);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSelectComponentOwnerActor()
|
|
{
|
|
return GEditor->GetSelectedComponentCount() > 0;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectAllActorsControlledByMatinee()
|
|
{
|
|
GEditor->SelectAllActorsControlledByMatinee();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectOwningHLODCluster()
|
|
{
|
|
if (GEditor->GetSelectedActorCount() > 0)
|
|
{
|
|
AActor* Actor = Cast<AActor>(GEditor->GetSelectedActors()->GetSelectedObject(0));
|
|
|
|
FHierarchicalLODUtilitiesModule& Module = FModuleManager::LoadModuleChecked<FHierarchicalLODUtilitiesModule>("HierarchicalLODUtilities");
|
|
IHierarchicalLODUtilities* Utilities = Module.GetUtilities();
|
|
|
|
ALODActor* ParentActor = Utilities->GetParentLODActor(Actor);
|
|
if (Actor && ParentActor)
|
|
{
|
|
GEditor->SelectNone(false, true);
|
|
GEditor->SelectActor(ParentActor, true, false);
|
|
GEditor->NoteSelectionChange();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectMatineeActor( AMatineeActor * ActorToSelect )
|
|
{
|
|
GEditor->SelectNone( false, true );
|
|
GEditor->SelectActor(ActorToSelect, true, false, true);
|
|
|
|
GEditor->NoteSelectionChange();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectMatineeGroup( AActor* Actor )
|
|
{
|
|
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_InterpEdit ) )
|
|
{
|
|
FEdModeInterpEdit* InterpEditMode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit );
|
|
|
|
if ( InterpEditMode && InterpEditMode->MatineeActor )
|
|
{
|
|
InterpEditMode->UpdateSelectedActor();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnApplyMaterialToSurface()
|
|
{
|
|
FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast();
|
|
|
|
GUnrealEd->Exec( GetWorld(), TEXT("POLY SETMATERIAL") );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectAllLights()
|
|
{
|
|
GEditor->GetSelectedActors()->BeginBatchSelectOperation();
|
|
// Select all light actors.
|
|
for( ALight* Light : TActorRange<ALight>(GetWorld()) )
|
|
{
|
|
GUnrealEd->SelectActor( Light, true, false, false );
|
|
}
|
|
|
|
GEditor->GetSelectedActors()->EndBatchSelectOperation();
|
|
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectStationaryLightsExceedingOverlap()
|
|
{
|
|
GEditor->SelectNone( true, true );
|
|
for( FActorIterator It(GetWorld()); It; ++It )
|
|
{
|
|
AActor* Actor = *It;
|
|
|
|
TInlineComponentArray<ULightComponent*> Components;
|
|
Actor->GetComponents(Components);
|
|
|
|
for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
|
|
{
|
|
ULightComponent* LightComponent = Components[ComponentIndex];
|
|
|
|
if (LightComponent->GetOwner()
|
|
// Use the component's lighting properties to determine if this is a stationary light, instead of checking the actor type
|
|
// Because blueprint lights may be operating as stationary lights
|
|
&& LightComponent->HasStaticShadowing()
|
|
&& !LightComponent->HasStaticLighting()
|
|
&& LightComponent->bAffectsWorld
|
|
&& LightComponent->CastShadows
|
|
&& LightComponent->CastStaticShadows
|
|
&& LightComponent->PreviewShadowMapChannel == INDEX_NONE)
|
|
{
|
|
GUnrealEd->SelectActor( LightComponent->GetOwner(), true, true, false );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSurfaceAlignment( ETexAlign AlignmentMode )
|
|
{
|
|
GTexAlignTools.GetAligner( AlignmentMode )->Align( GetWorld(), AlignmentMode );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::RegroupActor_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->GroupSelected();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::UngroupActor_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->UngroupSelected();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::LockGroup_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->LockSelectedGroups();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::UnlockGroup_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->UnlockSelectedGroups();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::AddActorsToGroup_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->AddSelectedToGroup();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::RemoveActorsFromGroup_Clicked()
|
|
{
|
|
UActorGroupingUtils::Get()->RemoveSelectedFromGroup();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::LocationGridSnap_Clicked()
|
|
{
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("MODE GRID=%d"), !GetDefault<ULevelEditorViewportSettings>()->GridEnabled ? 1 : 0 ) );
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::LocationGridSnap_IsChecked()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->GridEnabled;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::RotationGridSnap_Clicked()
|
|
{
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("MODE ROTGRID=%d"), !GetDefault<ULevelEditorViewportSettings>()->RotGridEnabled ? 1 : 0 ) );
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::RotationGridSnap_IsChecked()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->RotGridEnabled;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ScaleGridSnap_Clicked()
|
|
{
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("MODE SCALEGRID=%d"), !GetDefault<ULevelEditorViewportSettings>()->SnapScaleEnabled ? 1 : 0 ) );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::ScaleGridSnap_IsChecked()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->SnapScaleEnabled;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::SaveAnimationFromSkeletalMeshComponent(AActor * EditorActor, AActor * SimActor, TArray<class USkeletalMeshComponent*> & OutEditorComponents)
|
|
{
|
|
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") );
|
|
|
|
// currently blueprint actors don't work because their property can't get copied over.
|
|
if (Cast<UBlueprintGeneratedClass>(EditorActor->GetClass()) != nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// find all skel components
|
|
TInlineComponentArray<class USkeletalMeshComponent *> SimSkelComponents;
|
|
SimActor->GetComponents<USkeletalMeshComponent>(SimSkelComponents);
|
|
|
|
if(SimSkelComponents.Num() > 0)
|
|
{
|
|
// see if simulating,
|
|
bool bSimulating = false;
|
|
for (auto & Comp : SimSkelComponents)
|
|
{
|
|
bSimulating |= (Comp->SkeletalMesh && Comp->SkeletalMesh->Skeleton && Comp->IsSimulatingPhysics());
|
|
}
|
|
|
|
// if any of them are legitimately simulating
|
|
if (bSimulating)
|
|
{
|
|
// ask users if you'd like to make an animation
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("ActorName"), FText::FromString(GetNameSafe(EditorActor)));
|
|
FText AskQuestion = FText::Format(LOCTEXT("KeepSimulationChanges_AskSaveAnimation", "Would you like to save animations from simulation for {ActorName} actor"), Args);
|
|
if(EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, AskQuestion))
|
|
{
|
|
for (auto & Comp : SimSkelComponents)
|
|
{
|
|
if (Comp->SkeletalMesh && Comp->SkeletalMesh->Skeleton && Comp->IsSimulatingPhysics())
|
|
{
|
|
// now record to animation
|
|
class UAnimSequence* Sequence = LevelEditorModule.OnCaptureSingleFrameAnimSequence().IsBound() ? LevelEditorModule.OnCaptureSingleFrameAnimSequence().Execute(Comp) : nullptr;
|
|
if(Sequence)
|
|
{
|
|
Comp->SetAnimationMode(EAnimationMode::AnimationSingleNode);
|
|
Comp->AnimationData.AnimToPlay = Sequence;
|
|
Comp->SetAnimation(Sequence);
|
|
Comp->SetSimulatePhysics(false);
|
|
|
|
// add the matching component to EditorCompoennts
|
|
class USkeletalMeshComponent * MatchingComponent = Cast<USkeletalMeshComponent>(EditorUtilities::FindMatchingComponentInstance(Comp, EditorActor));
|
|
if (MatchingComponent)
|
|
{
|
|
OutEditorComponents.Add(MatchingComponent);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LevelEditorActions, Warning, TEXT("Matching component could not be found %s(%s)"), *GetNameSafe(Comp), *GetNameSafe(EditorActor));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenMergeActor_Clicked()
|
|
{
|
|
FGlobalTabmanager::Get()->InvokeTab(FName("MergeActors"));
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnKeepSimulationChanges()
|
|
{
|
|
// @todo simulate: There are lots of types of changes that can't be "kept", like attachment or newly-spawned actors. This
|
|
// feature currently only supports propagating changes to regularly-editable properties on an instance of a PIE actor
|
|
// that still exists in the editor world.
|
|
|
|
// Make sure we have some actors selected, and PIE is running
|
|
if( GEditor->GetSelectedActorCount() > 0 && GEditor->PlayWorld != NULL )
|
|
{
|
|
int32 UpdatedActorCount = 0;
|
|
int32 TotalCopiedPropertyCount = 0;
|
|
FString FirstUpdatedActorLabel;
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT( "LevelEditorCommands", "KeepSimulationChanges", "Keep Simulation Changes" ) );
|
|
|
|
TArray<class USkeletalMeshComponent*> ComponentsToReinitialize;
|
|
|
|
for( auto ActorIt( GEditor->GetSelectedActorIterator() ); ActorIt; ++ActorIt )
|
|
{
|
|
auto* SimWorldActor = CastChecked<AActor>( *ActorIt );
|
|
|
|
// Find our counterpart actor
|
|
AActor* EditorWorldActor = EditorUtilities::GetEditorWorldCounterpartActor( SimWorldActor );
|
|
if( EditorWorldActor != NULL )
|
|
{
|
|
SaveAnimationFromSkeletalMeshComponent(EditorWorldActor, SimWorldActor, ComponentsToReinitialize);
|
|
|
|
// We only want to copy CPF_Edit properties back, or properties that are set through editor manipulation
|
|
// NOTE: This needs to match what we're doing in the BuildSelectedActorInfo() function
|
|
const auto CopyOptions = ( EditorUtilities::ECopyOptions::Type )(
|
|
EditorUtilities::ECopyOptions::CallPostEditChangeProperty |
|
|
EditorUtilities::ECopyOptions::CallPostEditMove |
|
|
EditorUtilities::ECopyOptions::OnlyCopyEditOrInterpProperties |
|
|
EditorUtilities::ECopyOptions::FilterBlueprintReadOnly);
|
|
const int32 CopiedPropertyCount = EditorUtilities::CopyActorProperties( SimWorldActor, EditorWorldActor, CopyOptions );
|
|
|
|
if( CopiedPropertyCount > 0 )
|
|
{
|
|
++UpdatedActorCount;
|
|
TotalCopiedPropertyCount += CopiedPropertyCount;
|
|
|
|
if( FirstUpdatedActorLabel.IsEmpty() )
|
|
{
|
|
FirstUpdatedActorLabel = EditorWorldActor->GetActorLabel();
|
|
}
|
|
}
|
|
}
|
|
|
|
// need to reinitialize animation
|
|
for (auto MeshComp : ComponentsToReinitialize)
|
|
{
|
|
if(MeshComp->SkeletalMesh)
|
|
{
|
|
MeshComp->InitAnim(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Let the user know what happened
|
|
{
|
|
FNotificationInfo NotificationInfo( FText::GetEmpty() );
|
|
NotificationInfo.bFireAndForget = true;
|
|
NotificationInfo.FadeInDuration = 0.25f;
|
|
NotificationInfo.FadeOutDuration = 1.0f;
|
|
NotificationInfo.ExpireDuration = 1.0f;
|
|
NotificationInfo.bUseLargeFont = false;
|
|
NotificationInfo.bUseSuccessFailIcons = true;
|
|
NotificationInfo.bAllowThrottleWhenFrameRateIsLow = false; // Don't throttle as it causes distracting hitches in Simulate mode
|
|
SNotificationItem::ECompletionState CompletionState;
|
|
if( UpdatedActorCount > 0 )
|
|
{
|
|
if( UpdatedActorCount > 1 )
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT("UpdatedActorCount"), UpdatedActorCount );
|
|
Args.Add( TEXT("TotalCopiedPropertyCount"), TotalCopiedPropertyCount );
|
|
NotificationInfo.Text = FText::Format( NSLOCTEXT( "LevelEditorCommands", "KeepSimulationChanges_MultipleActorsUpdatedNotification", "Saved state for {UpdatedActorCount} actors ({TotalCopiedPropertyCount} properties)" ), Args );
|
|
}
|
|
else
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add( TEXT("FirstUpdatedActorLabel"), FText::FromString( FirstUpdatedActorLabel ) );
|
|
Args.Add( TEXT("TotalCopiedPropertyCount"), TotalCopiedPropertyCount );
|
|
NotificationInfo.Text = FText::Format( NSLOCTEXT( "LevelEditorCommands", "KeepSimulationChanges_ActorUpdatedNotification", "Saved state for {FirstUpdatedActorLabel} ({TotalCopiedPropertyCount} properties)" ), Args );
|
|
}
|
|
CompletionState = SNotificationItem::CS_Success;
|
|
}
|
|
else
|
|
{
|
|
NotificationInfo.Text = NSLOCTEXT( "LevelEditorCommands", "KeepSimulationChanges_NoActorsUpdated", "No properties were copied" );
|
|
CompletionState = SNotificationItem::CS_Fail;
|
|
}
|
|
const auto Notification = FSlateNotificationManager::Get().AddNotification( NotificationInfo );
|
|
Notification->SetCompletionState( CompletionState );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::CanExecuteKeepSimulationChanges()
|
|
{
|
|
return AssetSelectionUtils::GetSelectedActorInfo().NumSimulationChanges > 0;
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::OnMakeSelectedActorLevelCurrent()
|
|
{
|
|
GUnrealEd->MakeSelectedActorsLevelCurrent();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnMoveSelectedToCurrentLevel()
|
|
{
|
|
UEditorLevelUtils::MoveSelectedActorsToLevel(GetWorld()->GetCurrentLevel());
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnFindActorLevelInContentBrowser()
|
|
{
|
|
GEditor->SyncActorLevelsToContentBrowser();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanExecuteFindActorLevelInContentBrowser()
|
|
{
|
|
return GEditor->CanSyncActorLevelsToContentBrowser();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnFindLevelsInLevelBrowser()
|
|
{
|
|
const bool bDeselectOthers = true;
|
|
GEditor->SelectLevelInLevelBrowser( bDeselectOthers );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnSelectLevelInLevelBrowser()
|
|
{
|
|
const bool bDeselectOthers = false;
|
|
GEditor->SelectLevelInLevelBrowser( bDeselectOthers );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnDeselectLevelInLevelBrowser()
|
|
{
|
|
GEditor->DeselectLevelInLevelBrowser();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnFindActorInLevelScript()
|
|
{
|
|
GUnrealEd->FindSelectedActorsInLevelScript();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnShowWorldProperties( TWeakPtr< SLevelEditor > LevelEditor )
|
|
{
|
|
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>( TEXT("LevelEditor") );
|
|
LevelEditorModule.GetLevelEditorTabManager()->InvokeTab(FName("WorldSettingsTab"));
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenContentBrowser()
|
|
{
|
|
FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
|
|
ContentBrowserModule.Get().FocusPrimaryContentBrowser(true);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenMarketplace()
|
|
{
|
|
FUnrealEdMisc::Get().OpenMarketplace();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::ToggleVR()
|
|
{
|
|
IVREditorModule& VREditorModule = IVREditorModule::Get();
|
|
VREditorModule.EnableVREditor( !VREditorModule.IsVREditorEnabled() );
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::ToggleVR_CanExecute()
|
|
{
|
|
IVREditorModule& VREditorModule = IVREditorModule::Get();
|
|
return VREditorModule.IsVREditorAvailable();
|
|
}
|
|
|
|
|
|
bool FLevelEditorActionCallbacks::ToggleVR_IsChecked()
|
|
{
|
|
IVREditorModule& VREditorModule = IVREditorModule::Get();
|
|
return VREditorModule.IsVREditorEnabled();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSelectGameModeBlueprint()
|
|
{
|
|
bool bCheckOutNeeded = false;
|
|
|
|
FString ConfigFilePath = FPaths::ConvertRelativePathToFull(FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()));
|
|
if(ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
// note: calling QueueStatusUpdate often does not spam status updates as an internal timer prevents this
|
|
//ISourceControlModule::Get().QueueStatusUpdate(ConfigFilePath);
|
|
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(ConfigFilePath, EStateCacheUsage::Use);
|
|
bCheckOutNeeded = SourceControlState.IsValid() && SourceControlState->CanCheckout();
|
|
}
|
|
else
|
|
{
|
|
bCheckOutNeeded = (FPaths::FileExists(ConfigFilePath) && IFileManager::Get().IsReadOnly(*ConfigFilePath));
|
|
}
|
|
return !bCheckOutNeeded;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OpenLevelBlueprint( TWeakPtr< SLevelEditor > LevelEditor )
|
|
{
|
|
if( LevelEditor.Pin()->GetWorld()->GetCurrentLevel() )
|
|
{
|
|
ULevelScriptBlueprint* LevelScriptBlueprint = LevelEditor.Pin()->GetWorld()->PersistentLevel->GetLevelScriptBlueprint();
|
|
if (LevelScriptBlueprint)
|
|
{
|
|
// @todo Re-enable once world centric works
|
|
const bool bOpenWorldCentric = false;
|
|
FAssetEditorManager::Get().OpenEditorForAsset(
|
|
LevelScriptBlueprint,
|
|
bOpenWorldCentric ? EToolkitMode::WorldCentric : EToolkitMode::Standalone,
|
|
LevelEditor.Pin() );
|
|
}
|
|
else
|
|
{
|
|
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToCreateLevelScript", "Unable to find or create a level blueprint for this level.") );
|
|
}
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::CreateBlankBlueprintClass()
|
|
{
|
|
// Use the BlueprintFactory to allow the user to pick a parent class for the new Blueprint class
|
|
UBlueprintFactory* NewFactory = Cast<UBlueprintFactory>(NewObject<UFactory>(GetTransientPackage(), UBlueprintFactory::StaticClass()));
|
|
FEditorDelegates::OnConfigureNewAssetProperties.Broadcast(NewFactory);
|
|
if ( NewFactory->ConfigureProperties() )
|
|
{
|
|
UClass* SelectedClass = NewFactory->ParentClass;
|
|
|
|
// Now help the user pick a path and name for the new Blueprint
|
|
UBlueprint* Blueprint = FKismetEditorUtilities::CreateBlueprintFromClass(NSLOCTEXT("LevelEditorCommands", "CreateBlankBlueprintClass_Title", "Create Blank Blueprint Class"), SelectedClass);
|
|
|
|
if( Blueprint )
|
|
{
|
|
// @todo Re-enable once world centric works
|
|
const bool bOpenWorldCentric = false;
|
|
FAssetEditorManager::Get().OpenEditorForAsset(
|
|
Blueprint,
|
|
bOpenWorldCentric ? EToolkitMode::WorldCentric : EToolkitMode::Standalone);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanHarvestSelectedActorsIntoBlueprintClass()
|
|
{
|
|
return GEditor->GetSelectedActorCount() > 0;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::HarvestSelectedActorsIntoBlueprintClass()
|
|
{
|
|
const bool bHarvest = true;
|
|
FCreateBlueprintFromActorDialog::OpenDialog(bHarvest);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSubclassSelectedActorIntoBlueprintClass()
|
|
{
|
|
bool bCanSubclass = GEditor->GetSelectedActorCount() == 1;
|
|
if (bCanSubclass)
|
|
{
|
|
AActor* Actor = Cast<AActor>(*GEditor->GetSelectedActorIterator());
|
|
bCanSubclass = FKismetEditorUtilities::CanCreateBlueprintOfClass(Actor->GetClass());
|
|
}
|
|
return bCanSubclass;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SubclassSelectedActorIntoBlueprintClass()
|
|
{
|
|
const bool bHarvest = false;
|
|
FCreateBlueprintFromActorDialog::OpenDialog(bHarvest);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::CheckOutProjectSettingsConfig( )
|
|
{
|
|
FString ConfigFilePath = FPaths::ConvertRelativePathToFull(FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()));
|
|
if(ISourceControlModule::Get().IsEnabled())
|
|
{
|
|
SourceControlHelpers::CheckOutFile(ConfigFilePath);
|
|
}
|
|
else
|
|
{
|
|
FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*ConfigFilePath, false);
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnShowOnlySelectedActors()
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT( "LevelEditorCommands", "ShowOnlySelectedActors", "Show Only Selected Actors" ) );
|
|
// First hide unselected as this will also hide group actor members
|
|
GUnrealEd->edactHideUnselected( GetWorld() );
|
|
// Then unhide selected to ensure that everything that's selected will be unhidden
|
|
GUnrealEd->edactUnhideSelected(GetWorld());
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleTransformWidgetVisibility()
|
|
{
|
|
GLevelEditorModeTools().SetShowWidget( !GLevelEditorModeTools().GetShowWidget() );
|
|
GUnrealEd->RedrawAllViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnGetTransformWidgetVisibility()
|
|
{
|
|
return GLevelEditorModeTools().GetShowWidget();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAllowTranslucentSelection()
|
|
{
|
|
auto* Settings = GetMutableDefault<UEditorPerProjectUserSettings>();
|
|
|
|
// Toggle 'allow select translucent'
|
|
Settings->bAllowSelectTranslucent = !Settings->bAllowSelectTranslucent;
|
|
Settings->PostEditChange();
|
|
|
|
// Need to refresh hit proxies as we changed what should be rendered into them
|
|
GUnrealEd->RedrawAllViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsAllowTranslucentSelectionEnabled()
|
|
{
|
|
return GetDefault<UEditorPerProjectUserSettings>()->bAllowSelectTranslucent == true;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAllowGroupSelection()
|
|
{
|
|
AGroupActor::ToggleGroupMode();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsAllowGroupSelectionEnabled()
|
|
{
|
|
return UActorGroupingUtils::IsGroupingActive();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleStrictBoxSelect()
|
|
{
|
|
ULevelEditorViewportSettings* ViewportSettings = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
ViewportSettings->bStrictBoxSelection = !ViewportSettings->bStrictBoxSelection;
|
|
ViewportSettings->PostEditChange();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsStrictBoxSelectEnabled()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->bStrictBoxSelection;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleTransparentBoxSelect()
|
|
{
|
|
ULevelEditorViewportSettings* ViewportSettings = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
ViewportSettings->bTransparentBoxSelection = !ViewportSettings->bTransparentBoxSelection;
|
|
ViewportSettings->PostEditChange();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsTransparentBoxSelectEnabled()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->bTransparentBoxSelection;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnDrawBrushMarkerPolys()
|
|
{
|
|
GEditor->Exec( GetWorld(), *FString::Printf( TEXT("MODE SHOWBRUSHMARKERPOLYS=%d"), !GEditor->bShowBrushMarkerPolys ? 1 : 0 ) );
|
|
GEditor->SaveConfig();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsDrawBrushMarkerPolysEnabled()
|
|
{
|
|
return GEditor->bShowBrushMarkerPolys;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleOnlyLoadVisibleInPIE()
|
|
{
|
|
ULevelEditorPlaySettings* PlaySettings = GetMutableDefault<ULevelEditorPlaySettings>();
|
|
PlaySettings->bOnlyLoadVisibleLevelsInPIE = !PlaySettings->bOnlyLoadVisibleLevelsInPIE;
|
|
PlaySettings->PostEditChange();
|
|
PlaySettings->SaveConfig();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsOnlyLoadVisibleInPIEEnabled()
|
|
{
|
|
return GetDefault<ULevelEditorPlaySettings>()->bOnlyLoadVisibleLevelsInPIE;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleSocketSnapping()
|
|
{
|
|
GEditor->bEnableSocketSnapping = !GEditor->bEnableSocketSnapping;
|
|
GEditor->RedrawLevelEditingViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsSocketSnappingEnabled()
|
|
{
|
|
return GEditor->bEnableSocketSnapping;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleParticleSystemLOD()
|
|
{
|
|
GEngine->bEnableEditorPSysRealtimeLOD = !GEngine->bEnableEditorPSysRealtimeLOD;
|
|
GEditor->RedrawLevelEditingViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsParticleSystemLODEnabled()
|
|
{
|
|
return GEditor->bEnableEditorPSysRealtimeLOD;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleFreezeParticleSimulation()
|
|
{
|
|
IConsoleManager& ConsoleManager = IConsoleManager::Get();
|
|
IConsoleVariable* CVar = ConsoleManager.FindConsoleVariable(TEXT("FX.FreezeParticleSimulation"));
|
|
if (CVar)
|
|
{
|
|
CVar->Set(CVar->GetInt() == 0 ? 1 : 0, ECVF_SetByConsole);
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsParticleSimulationFrozen()
|
|
{
|
|
IConsoleManager& ConsoleManager = IConsoleManager::Get();
|
|
static const auto* CVar = ConsoleManager.FindConsoleVariable(TEXT("FX.FreezeParticleSimulation"));
|
|
if (CVar)
|
|
{
|
|
return CVar->GetInt() != 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleParticleSystemHelpers()
|
|
{
|
|
GEditor->bDrawParticleHelpers = !GEditor->bDrawParticleHelpers;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsParticleSystemHelpersEnabled()
|
|
{
|
|
return GEditor->bDrawParticleHelpers;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleLODViewLocking()
|
|
{
|
|
GEditor->bEnableLODLocking = !GEditor->bEnableLODLocking;
|
|
GEditor->RedrawLevelEditingViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsLODViewLockingEnabled()
|
|
{
|
|
return GEditor->bEnableLODLocking;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleLevelStreamingVolumePrevis()
|
|
{
|
|
ULevelEditorViewportSettings* ViewportSettings = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
|
|
ViewportSettings->bLevelStreamingVolumePrevis = !ViewportSettings->bLevelStreamingVolumePrevis;
|
|
ViewportSettings->PostEditChange();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsLevelStreamingVolumePrevisEnabled()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->bLevelStreamingVolumePrevis;
|
|
}
|
|
|
|
FText FLevelEditorActionCallbacks::GetAudioVolumeToolTip()
|
|
{
|
|
if ( !GEditor->IsRealTimeAudioMuted() )
|
|
{
|
|
const float Volume = GEditor->GetRealTimeAudioVolume() * 100.0f;
|
|
return FText::AsNumber( FMath::RoundToInt(Volume) );
|
|
}
|
|
return NSLOCTEXT("UnrealEd", "Muted", "Muted" );
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetAudioVolume()
|
|
{
|
|
return GEditor->GetRealTimeAudioVolume();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAudioVolumeChanged(float Volume)
|
|
{
|
|
GEditor->SetRealTimeAudioVolume(Volume);
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::GetAudioMuted()
|
|
{
|
|
return GEditor->IsRealTimeAudioMuted();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAudioMutedChanged(bool bMuted)
|
|
{
|
|
GEditor->MuteRealTimeAudio(bMuted);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SnapObjectToView_Clicked()
|
|
{
|
|
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "SnapObjectToView", "Snap Object to View"));
|
|
for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It)
|
|
{
|
|
AActor* Actor = Cast<AActor>(*It);
|
|
Actor->Modify();
|
|
FVector Location = GCurrentLevelEditingViewportClient->GetViewLocation();
|
|
FRotator Rotation = GCurrentLevelEditingViewportClient->GetViewRotation();
|
|
|
|
Actor->SetActorLocation(Location);
|
|
Actor->SetActorRotation(Rotation);
|
|
}
|
|
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnEnableActorSnap()
|
|
{
|
|
FSnappingUtils::EnableActorSnap( !FSnappingUtils::IsSnapToActorEnabled() );
|
|
|
|
// If the setting is enabled and there's no distance, revert to default
|
|
if ( FSnappingUtils::IsSnapToActorEnabled() && FSnappingUtils::GetActorSnapDistance() == 0.0f )
|
|
{
|
|
FSnappingUtils::SetActorSnapDistance( 1.0f );
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsActorSnapEnabled()
|
|
{
|
|
return FSnappingUtils::IsSnapToActorEnabled();
|
|
}
|
|
|
|
|
|
void FLevelEditorActionCallbacks::OnEnableVertexSnap()
|
|
{
|
|
ULevelEditorViewportSettings* ViewportSettings = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
ViewportSettings->bSnapVertices = !ViewportSettings->bSnapVertices;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::OnIsVertexSnapEnabled()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->bSnapVertices;
|
|
}
|
|
|
|
FText FLevelEditorActionCallbacks::GetActorSnapTooltip()
|
|
{
|
|
// If the setting is enabled, return the distance, otherwise say disabled
|
|
if ( FSnappingUtils::IsSnapToActorEnabled() )
|
|
{
|
|
static const FNumberFormattingOptions FormatOptions = FNumberFormattingOptions()
|
|
.SetMinimumFractionalDigits(2)
|
|
.SetMaximumFractionalDigits(2);
|
|
return FText::AsNumber( FSnappingUtils::GetActorSnapDistance(), &FormatOptions );
|
|
}
|
|
return NSLOCTEXT("UnrealEd", "Disabled", "Disabled" );
|
|
}
|
|
|
|
float FLevelEditorActionCallbacks::GetActorSnapSetting()
|
|
{
|
|
// If the setting is enabled, return the distance, otherwise say 0
|
|
if (FSnappingUtils::IsSnapToActorEnabled() )
|
|
{
|
|
return FSnappingUtils::GetActorSnapDistance(true) ;
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetActorSnapSetting(float Distance)
|
|
{
|
|
FSnappingUtils::SetActorSnapDistance( Distance );
|
|
|
|
// If the distance is 0, disable the setting until it's > 0
|
|
FSnappingUtils::EnableActorSnap( ( Distance > 0.0f ? true : false ) );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnToggleHideViewportUI()
|
|
{
|
|
GLevelEditorModeTools().SetHideViewportUI( !GLevelEditorModeTools().IsViewportUIHidden() );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsViewportUIHidden()
|
|
{
|
|
return GLevelEditorModeTools().IsViewportUIHidden();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsEditorModeActive( FEditorModeID EditorMode )
|
|
{
|
|
return GLevelEditorModeTools().IsModeActive( EditorMode );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAddVolume( UClass* VolumeClass )
|
|
{
|
|
GUnrealEd->Exec( GetWorld(), *FString::Printf( TEXT("BRUSH ADDVOLUME CLASS=%s"), *VolumeClass->GetName() ) );
|
|
|
|
// A new volume actor was added, update the volumes visibility.
|
|
// This volume should be hidden if the user doesn't have this type of volume visible.
|
|
GUnrealEd->UpdateVolumeActorVisibility( VolumeClass );
|
|
|
|
GEditor->RedrawAllViewports();
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::OnAddMatinee()
|
|
{
|
|
// Warn the user prior to creating our actor
|
|
if ( GEditor->ShouldOpenMatinee( NULL ) )
|
|
{
|
|
// Spawn a matinee actor at the origin, and either move infront of the camera or focus camera on it (depending on the viewport) and open for edit
|
|
UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass( AMatineeActor::StaticClass() );
|
|
check( ActorFactory );
|
|
AMatineeActor* MatineeActor = CastChecked<AMatineeActor>( FLevelEditorActionCallbacks::AddActor( ActorFactory, FAssetData(), &FTransform::Identity ) );
|
|
if( GCurrentLevelEditingViewportClient->IsPerspective() )
|
|
{
|
|
GEditor->MoveActorInFrontOfCamera( *MatineeActor, GCurrentLevelEditingViewportClient->GetViewLocation(), GCurrentLevelEditingViewportClient->GetViewRotation().Vector() );
|
|
}
|
|
else
|
|
{
|
|
GEditor->MoveViewportCamerasToActor( *MatineeActor, false );
|
|
}
|
|
GEditor->OpenMatinee( MatineeActor, false );
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SelectActorsInLayers()
|
|
{
|
|
// Iterate over selected actors and make a list of all layers the selected actors belong to.
|
|
TArray< FName > SelectedLayers;
|
|
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
|
|
{
|
|
AActor* Actor = Cast<AActor>( *It );
|
|
|
|
// Add them to the list of selected layers.
|
|
for( int32 LayerIndex = 0 ; LayerIndex < Actor->Layers.Num() ; ++LayerIndex )
|
|
{
|
|
SelectedLayers.AddUnique( Actor->Layers[ LayerIndex ] );
|
|
}
|
|
}
|
|
|
|
bool bSelect = true;
|
|
bool bNotify = true;
|
|
GEditor->Layers->SelectActorsInLayers( SelectedLayers, bSelect, bNotify );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetWidgetMode( FWidget::EWidgetMode WidgetMode )
|
|
{
|
|
if( !GLevelEditorModeTools().IsTracking() )
|
|
{
|
|
GLevelEditorModeTools().SetWidgetMode( WidgetMode );
|
|
GEditor->RedrawAllViewports();
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsWidgetModeActive( FWidget::EWidgetMode WidgetMode )
|
|
{
|
|
return GLevelEditorModeTools().GetWidgetMode() == WidgetMode;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSetWidgetMode( FWidget::EWidgetMode WidgetMode )
|
|
{
|
|
return GLevelEditorModeTools().UsesTransformWidget(WidgetMode) == true;
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsTranslateRotateModeVisible()
|
|
{
|
|
return GetDefault<ULevelEditorViewportSettings>()->bAllowTranslateRotateZWidget;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SetCoordinateSystem( ECoordSystem CoordinateSystem )
|
|
{
|
|
GLevelEditorModeTools().SetCoordSystem( CoordinateSystem );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::IsCoordinateSystemActive( ECoordSystem CoordinateSystem )
|
|
{
|
|
return GLevelEditorModeTools().GetCoordSystem() == CoordinateSystem;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::MoveActorToGrid_Clicked( bool InAlign, bool bInPerActor )
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "MoveActorToGrid", "Snap Origin to Grid") );
|
|
MoveActorTo_Clicked( InAlign, NULL, bInPerActor );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::MoveActorToActor_Clicked( bool InAlign )
|
|
{
|
|
AActor* Actor = GEditor->GetSelectedActors()->GetBottom<AActor>();
|
|
if( Actor )
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "MoveActorToActor", "Snap Origin to Actor") );
|
|
MoveActorTo_Clicked( InAlign, Actor );
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::MoveActorTo_Clicked( const bool InAlign, const AActor* InDestination/* = NULL*/, bool bInPerActor/* = false*/ )
|
|
{
|
|
// Fires ULevel::LevelDirtiedEvent when falling out of scope.
|
|
FScopedLevelDirtied LevelDirtyCallback;
|
|
|
|
// Update the pivot location.
|
|
FVector Delta = FVector::ZeroVector;
|
|
FVector NewLocation = FVector::ZeroVector;
|
|
FRotator NewRotation = FRotator::ZeroRotator;
|
|
|
|
if(!bInPerActor)
|
|
{
|
|
if ( InDestination )
|
|
{
|
|
NewLocation = InDestination->GetActorLocation();
|
|
NewRotation = InDestination->GetActorRotation();
|
|
GEditor->SetPivot( NewLocation, false, true );
|
|
}
|
|
else
|
|
{
|
|
const FVector OldPivot = GEditor->GetPivotLocation();
|
|
const FVector NewPivot = OldPivot.GridSnap(GEditor->GetGridSize());
|
|
Delta = NewPivot - OldPivot;
|
|
GEditor->SetPivot( NewPivot, false, true );
|
|
}
|
|
}
|
|
|
|
for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It )
|
|
{
|
|
AActor* Actor = Cast<AActor>( *It );
|
|
checkSlow( Actor );
|
|
if ( Actor == InDestination ) // Early out
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Actor->Modify();
|
|
|
|
if(!InDestination)
|
|
{
|
|
if ( bInPerActor )
|
|
{
|
|
const FVector OldPivot = Actor->GetActorLocation();
|
|
const FVector NewPivot = OldPivot.GridSnap(GEditor->GetGridSize());
|
|
Delta = NewPivot - OldPivot;
|
|
GEditor->SetPivot( NewPivot, false, true );
|
|
}
|
|
|
|
NewLocation = Actor->GetActorLocation() + Delta;
|
|
}
|
|
|
|
Actor->TeleportTo( NewLocation, ( !InAlign ? Actor->GetActorRotation() : NewRotation ), false, true );
|
|
Actor->InvalidateLightingCache();
|
|
Actor->UpdateComponentTransforms();
|
|
|
|
Actor->MarkPackageDirty();
|
|
LevelDirtyCallback.Request();
|
|
}
|
|
|
|
GEditor->RedrawLevelEditingViewports();
|
|
GEditor->RebuildAlteredBSP(); // Update the Bsp of any levels containing a modified brush
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SnapTo2DLayer_Clicked()
|
|
{
|
|
// Fires ULevel::LevelDirtiedEvent when falling out of scope.
|
|
FScopedLevelDirtied LevelDirtyCallback;
|
|
|
|
const ULevelEditorViewportSettings* ViewportSettings = GetDefault<ULevelEditorViewportSettings>();
|
|
const ULevelEditor2DSettings* Settings2D = GetDefault<ULevelEditor2DSettings>();
|
|
if (Settings2D->SnapLayers.IsValidIndex(ViewportSettings->ActiveSnapLayerIndex))
|
|
{
|
|
const FScopedTransaction Transaction(NSLOCTEXT("UnrealEd", "SnapSelection2D", "Snap Selection to 2D Layer"));
|
|
|
|
float SnapDepth = Settings2D->SnapLayers[ViewportSettings->ActiveSnapLayerIndex].Depth;
|
|
USelection* SelectedActors = GEditor->GetSelectedActors();
|
|
for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter)
|
|
{
|
|
AActor* Actor = CastChecked<AActor>(*Iter);
|
|
|
|
// Only snap actors that are not attached to something else
|
|
if (Actor->GetAttachParentActor() == nullptr)
|
|
{
|
|
FTransform Transform = Actor->GetTransform();
|
|
FVector CurrentLocation = Transform.GetLocation();
|
|
|
|
switch (Settings2D->SnapAxis)
|
|
{
|
|
case ELevelEditor2DAxis::X: CurrentLocation.X = SnapDepth; break;
|
|
case ELevelEditor2DAxis::Y: CurrentLocation.Y = SnapDepth; break;
|
|
case ELevelEditor2DAxis::Z: CurrentLocation.Z = SnapDepth; break;
|
|
}
|
|
|
|
Transform.SetLocation(CurrentLocation);
|
|
Actor->Modify();
|
|
Actor->SetActorTransform(Transform);
|
|
|
|
Actor->InvalidateLightingCache();
|
|
Actor->UpdateComponentTransforms();
|
|
|
|
Actor->MarkPackageDirty();
|
|
LevelDirtyCallback.Request();
|
|
}
|
|
}
|
|
|
|
GEditor->RedrawLevelEditingViewports(true);
|
|
GEditor->RebuildAlteredBSP();
|
|
}
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanSnapTo2DLayer()
|
|
{
|
|
const ULevelEditor2DSettings* Settings = GetDefault<ULevelEditor2DSettings>();
|
|
return Settings->SnapLayers.IsValidIndex(GetDefault<ULevelEditorViewportSettings>()->ActiveSnapLayerIndex) && (GEditor->GetSelectedActorCount() > 0);
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::MoveSelectionToDifferent2DLayer_Clicked(bool bGoingUp, bool bForceToTopOrBottom)
|
|
{
|
|
// Change the active layer first
|
|
const ULevelEditor2DSettings* Settings2D = GetDefault<ULevelEditor2DSettings>();
|
|
ULevelEditorViewportSettings* SettingsVP = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
|
|
const int32 NumLayers = Settings2D->SnapLayers.Num();
|
|
|
|
if (NumLayers > 0)
|
|
{
|
|
if (bGoingUp && (SettingsVP->ActiveSnapLayerIndex > 0))
|
|
{
|
|
SettingsVP->ActiveSnapLayerIndex = bForceToTopOrBottom ? 0 : (SettingsVP->ActiveSnapLayerIndex - 1);
|
|
SettingsVP->PostEditChange();
|
|
}
|
|
else if (!bGoingUp && ((SettingsVP->ActiveSnapLayerIndex + 1) < NumLayers))
|
|
{
|
|
SettingsVP->ActiveSnapLayerIndex = bForceToTopOrBottom ? (NumLayers - 1) : (SettingsVP->ActiveSnapLayerIndex + 1);
|
|
SettingsVP->PostEditChange();
|
|
}
|
|
}
|
|
|
|
// Snap the selection to the new active layer
|
|
SnapTo2DLayer_Clicked();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::CanMoveSelectionToDifferent2DLayer(bool bGoingUp)
|
|
{
|
|
const ULevelEditor2DSettings* Settings2D = GetDefault<ULevelEditor2DSettings>();
|
|
const ULevelEditorViewportSettings* SettingsVP = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
|
|
const int32 SelectedIndex = SettingsVP->ActiveSnapLayerIndex;
|
|
const int32 NumLayers = Settings2D->SnapLayers.Num();
|
|
|
|
const bool bHasLayerInDirection = bGoingUp ? (SelectedIndex > 0) : (SelectedIndex + 1 < NumLayers);
|
|
const bool bHasActorSelected = GEditor->GetSelectedActorCount() > 0;
|
|
|
|
// Allow it even if there is no layer in the corresponding direction, to let it double as a snap operation shortcut even when at the end stops
|
|
return bHasLayerInDirection || bHasActorSelected;
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::Select2DLayerDeltaAway_Clicked(int32 Delta)
|
|
{
|
|
const ULevelEditor2DSettings* Settings2D = GetDefault<ULevelEditor2DSettings>();
|
|
ULevelEditorViewportSettings* SettingsVP = GetMutableDefault<ULevelEditorViewportSettings>();
|
|
|
|
const int32 SelectedIndex = SettingsVP->ActiveSnapLayerIndex;
|
|
const int32 NumLayers = Settings2D->SnapLayers.Num();
|
|
|
|
if (NumLayers > 0)
|
|
{
|
|
const int32 NewIndex = ((NumLayers + SelectedIndex + Delta) % NumLayers);
|
|
|
|
SettingsVP->ActiveSnapLayerIndex = NewIndex;
|
|
SettingsVP->PostEditChange();
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SnapToFloor_Clicked( bool InAlign, bool InUseLineTrace, bool InUseBounds, bool InUsePivot )
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "SnapActorsToFloor", "Snap Actors To Floor") );
|
|
SnapTo_Clicked( InAlign, InUseLineTrace, InUseBounds, InUsePivot );
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SnapActorToActor_Clicked( bool InAlign, bool InUseLineTrace, bool InUseBounds, bool InUsePivot )
|
|
{
|
|
AActor* Actor = GEditor->GetSelectedActors()->GetBottom<AActor>();
|
|
if( Actor )
|
|
{
|
|
const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "SnapActorsToActor", "Snap Actors To Actor") );
|
|
SnapTo_Clicked( InAlign, InUseLineTrace, InUseBounds, InUsePivot, Actor );
|
|
}
|
|
}
|
|
|
|
void FLevelEditorActionCallbacks::SnapTo_Clicked( const bool InAlign, const bool InUseLineTrace, const bool InUseBounds, const bool InUsePivot, AActor* InDestination )
|
|
{
|
|
// Fires ULevel::LevelDirtiedEvent when falling out of scope.
|
|
FScopedLevelDirtied LevelDirtyCallback;
|
|
|
|
bool bSnappedComponents = false;
|
|
if( GEditor->GetSelectedComponentCount() > 0 )
|
|
{
|
|
for(FSelectedEditableComponentIterator It(GEditor->GetSelectedEditableComponentIterator()); It; ++It)
|
|
{
|
|
USceneComponent* SceneComponent = Cast<USceneComponent>(*It);
|
|
if(SceneComponent)
|
|
{
|
|
SceneComponent->Modify();
|
|
AActor* ActorOwner = SceneComponent->GetOwner();
|
|
bSnappedComponents = true;
|
|
if(ActorOwner)
|
|
{
|
|
ActorOwner->Modify();
|
|
GEditor->SnapObjectTo(FActorOrComponent(SceneComponent), InAlign, InUseLineTrace, InUseBounds, InUsePivot, FActorOrComponent(InDestination));
|
|
ActorOwner->InvalidateLightingCache();
|
|
ActorOwner->UpdateComponentTransforms();
|
|
|
|
LevelDirtyCallback.Request();
|
|
}
|
|
}
|
|
}
|
|
|
|
USceneComponent* LastComp = GEditor->GetSelectedComponents()->GetBottom<USceneComponent>();
|
|
|
|
GEditor->SetPivot(LastComp->GetComponentLocation(), false, true);
|
|
}
|
|
|
|
if( !bSnappedComponents )
|
|
{
|
|
for(FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It)
|
|
{
|
|
AActor* Actor = Cast<AActor>(*It);
|
|
if(Actor)
|
|
{
|
|
Actor->Modify();
|
|
GEditor->SnapObjectTo(FActorOrComponent(Actor), InAlign, InUseLineTrace, InUseBounds, InUsePivot, FActorOrComponent(InDestination));
|
|
Actor->InvalidateLightingCache();
|
|
Actor->UpdateComponentTransforms();
|
|
|
|
LevelDirtyCallback.Request();
|
|
}
|
|
}
|
|
|
|
|
|
AActor* Actor = GEditor->GetSelectedActors()->GetBottom<AActor>();
|
|
if(Actor)
|
|
{
|
|
GEditor->SetPivot(Actor->GetActorLocation(), false, true);
|
|
|
|
if(UActorGroupingUtils::IsGroupingActive())
|
|
{
|
|
// set group pivot for the root-most group
|
|
AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(Actor, true, true);
|
|
if(ActorGroupRoot)
|
|
{
|
|
ActorGroupRoot->CenterGroupLocation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GEditor->RedrawLevelEditingViewports();
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::ActorSelected_CanExecute()
|
|
{
|
|
// Had to have something selected
|
|
return ( ( GEditor->GetSelectedActorCount() > 0 ) ? true : false );
|
|
}
|
|
|
|
bool FLevelEditorActionCallbacks::ActorsSelected_CanExecute()
|
|
{
|
|
// Has to have more than one selected
|
|
return ( ( GEditor->GetSelectedActorCount() > 1 ) ? true : false );
|
|
}
|
|
|
|
class UWorld* FLevelEditorActionCallbacks::GetWorld()
|
|
{
|
|
return GEditor->GetEditorWorldContext().World();
|
|
}
|
|
|
|
/** UI_COMMAND takes long for the compile to optimize */
|
|
PRAGMA_DISABLE_OPTIMIZATION
|
|
void FLevelEditorCommands::RegisterCommands()
|
|
{
|
|
UI_COMMAND( BrowseDocumentation, "Documentation...", "Opens the main documentation page, and allows you to search across all UE4 support sites.", EUserInterfaceActionType::Button, FInputChord( EKeys::F1 ) );
|
|
UI_COMMAND( BrowseAPIReference, "API Reference...", "Opens the API reference documentation", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BrowseCVars, "Console Variables", "Creates an HTML file to browse the console variables and commands (console command 'help')", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BrowseViewportControls, "Viewport Controls...", "Opens the viewport controls cheat sheet", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( NewLevel, "New Level...", "Create a new level, or choose a level template to start from.", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::N ) );
|
|
UI_COMMAND( OpenLevel, "Open Level...", "Loads an existing level", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::O ) );
|
|
UI_COMMAND( Save, "Save Current", "Saves the current level to disk", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control, EKeys::S) );
|
|
UI_COMMAND( SaveAs, "Save Current As...", "Save the current level as...", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control|EModifierKey::Alt, EKeys::S ) );
|
|
UI_COMMAND( SaveAllLevels, "Save All Levels", "Saves all unsaved levels to disk", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ToggleFavorite, "Toggle Favorite", "Sets whether the currently loaded level will appear in the list of favorite levels", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
for( int32 CurRecentIndex = 0; CurRecentIndex < FLevelEditorCommands::MaxRecentFiles; ++CurRecentIndex )
|
|
{
|
|
// NOTE: The actual label and tool-tip will be overridden at runtime when the command is bound to a menu item, however
|
|
// we still need to set one here so that the key bindings UI can function properly
|
|
TSharedRef< FUICommandInfo > OpenRecentFile =
|
|
FUICommandInfoDecl(
|
|
this->AsShared(),
|
|
FName( *FString::Printf( TEXT( "OpenRecentFile%i" ), CurRecentIndex ) ),
|
|
FText::Format( NSLOCTEXT( "LevelEditorCommands", "OpenRecentFile", "Open Recent File {0}" ), FText::AsNumber( CurRecentIndex ) ),
|
|
NSLOCTEXT( "LevelEditorCommands", "OpenRecentFileToolTip", "Opens a recently opened file" ) )
|
|
.UserInterfaceType( EUserInterfaceActionType::Button )
|
|
.DefaultChord( FInputChord() );
|
|
OpenRecentFileCommands.Add( OpenRecentFile );
|
|
}
|
|
for (int32 CurFavoriteIndex = 0; CurFavoriteIndex < FLevelEditorCommands::MaxRecentFiles; ++CurFavoriteIndex)
|
|
{
|
|
// NOTE: The actual label and tool-tip will be overridden at runtime when the command is bound to a menu item, however
|
|
// we still need to set one here so that the key bindings UI can function properly
|
|
TSharedRef< FUICommandInfo > OpenFavoriteFile =
|
|
FUICommandInfoDecl(
|
|
this->AsShared(),
|
|
FName(*FString::Printf(TEXT("OpenFavoriteFile%i"), CurFavoriteIndex)),
|
|
FText::Format(NSLOCTEXT("LevelEditorCommands", "OpenFavoriteFile", "Open Favorite File {0}"), FText::AsNumber(CurFavoriteIndex)),
|
|
NSLOCTEXT("LevelEditorCommands", "OpenFavoriteFileToolTip", "Opens a favorite file"))
|
|
.UserInterfaceType(EUserInterfaceActionType::Button)
|
|
.DefaultChord(FInputChord());
|
|
OpenFavoriteFileCommands.Add(OpenFavoriteFile);
|
|
}
|
|
|
|
UI_COMMAND( ImportScene, "Import Into Level...", "Imports a scene from a FBX or T3D format into the current level", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND( ExportAll, "Export All...", "Exports the entire level to a file on disk (multiple formats are supported.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ExportSelected, "Export Selected...", "Exports currently-selected objects to a file on disk (multiple formats are supported.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( Build, "Build All Levels", "Builds all levels (precomputes lighting data and visibility data, generates navigation networks and updates brush models.)\nThis action is not available while Play in Editor is active, or when previewing less than Shader Model 5", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildAndSubmitToSourceControl, "Build and Submit...", "Displays a window that allows you to build all levels and submit them to source control", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildLightingOnly, "Build Lighting", "Only precomputes lighting (all levels.)\nThis action is not available while Play in Editor is active, or when previewing less than Shader Model 5", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control|EModifierKey::Shift, EKeys::Semicolon) );
|
|
UI_COMMAND( BuildReflectionCapturesOnly, "Build Reflection Captures", "Updates Reflection Captures and stores their data in the BuildData package.\nThis action is not available while Play in Editor is active, or when previewing less than Shader Model 5", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildLightingOnly_VisibilityOnly, "Precompute Static Visibility", "Only precomputes static visibility data (all levels.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( LightingBuildOptions_UseErrorColoring, "Use Error Coloring", "When enabled, errors during lighting precomputation will be baked as colors into light map data", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( LightingBuildOptions_ShowLightingStats, "Show Lighting Stats", "When enabled, a window containing metrics about lighting performance and memory will be displayed after a successful build.", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( BuildGeometryOnly, "Build Geometry", "Only builds geometry (all levels.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildGeometryOnly_OnlyCurrentLevel, "Build Geometry (Current Level)", "Builds geometry, only for the current level", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildPathsOnly, "Build Paths", "Only builds paths (all levels.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildLODsOnly, "Build LODs", "Only builds LODs (all levels.)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( BuildTextureStreamingOnly, "Build Texture Streaming", "Build texture streaming data", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( LightingQuality_Production, "Production", "Sets precomputed lighting quality to highest possible quality (slowest computation time.)", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingQuality_High, "High", "Sets precomputed lighting quality to high quality", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingQuality_Medium, "Medium", "Sets precomputed lighting quality to medium quality", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingQuality_Preview, "Preview", "Sets precomputed lighting quality to preview quality (fastest computation time.)", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingDensity_RenderGrayscale, "Render Grayscale", "Renders the lightmap density.", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( LightingResolution_CurrentLevel, "Current Level", "Adjust only primitives in the current level.", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingResolution_SelectedLevels, "Selected Levels", "Adjust only primitives in the selected levels.", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingResolution_AllLoadedLevels, "All Loaded Levels", "Adjust primitives in all loaded levels.", EUserInterfaceActionType::RadioButton, FInputChord() );
|
|
UI_COMMAND( LightingResolution_SelectedObjectsOnly, "Selected Objects Only", "Adjust only selected objects in the levels.", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( LightingStaticMeshInfo, "Lighting StaticMesh Info...", "Shows the lighting information for the StaticMeshes.", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SceneStats, "Open Scene Stats", "Opens the Scene Stats viewer", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( TextureStats, "Open Texture Stats", "Opens the Texture Stats viewer", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MapCheck, "Open Map Check", "Checks map for errors", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( RecompileGameCode, "Recompile Game Code", "Recompiles and reloads C++ code for game systems on the fly", EUserInterfaceActionType::Button, FInputChord( EKeys::P, EModifierKey::Alt | EModifierKey::Control | EModifierKey::Shift ) );
|
|
|
|
UI_COMMAND( EditAsset, "Edit Asset", "Edits the asset associated with the selected actor", EUserInterfaceActionType::Button, FInputChord( EKeys::E, EModifierKey::Control ) );
|
|
UI_COMMAND( EditAssetNoConfirmMultiple, "Edit Asset", "Edits the asset associated with the selected actor", EUserInterfaceActionType::Button, FInputChord( EKeys::E, EModifierKey::Control | EModifierKey::Shift ) );
|
|
|
|
UI_COMMAND( GoHere, "Go Here", "Moves the camera to the current mouse position", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( SnapCameraToObject, "Snap View to Object", "Snaps the view to the selected object", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapObjectToCamera, "Snap Object to View", "Snaps the selected object to the view", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( GoToCodeForActor, "Go to C++ Code for Actor", "Opens a code editing IDE and navigates to the source file associated with the seleced actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( GoToDocsForActor, "Go to Documentation for Actor", "Opens documentation for the Actor in the default web browser", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( PasteHere, "Paste Here", "Pastes the actor at the click location", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( SnapOriginToGrid, "Snap Origin to Grid", "Snaps the actor to the nearest grid location at its origin", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::End ) );
|
|
UI_COMMAND( SnapOriginToGridPerActor, "Snap Origin to Grid Per Actor", "Snaps each selected actor separately to the nearest grid location at its origin", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AlignOriginToGrid, "Align Origin to Grid", "Aligns the actor to the nearest grid location at its origin", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( SnapTo2DLayer, "Snap to 2D Layer", "Snaps the actor to the current 2D snap layer", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::SpaceBar ) );
|
|
UI_COMMAND( MoveSelectionUpIn2DLayers, "Bring selection forward a snap layer", "Bring selection forward a snap layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageUp, EModifierKey::Control) );
|
|
UI_COMMAND( MoveSelectionDownIn2DLayers, "Send selection backward a snap layer", "Send selection backward a snap layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageDown, EModifierKey::Control) );
|
|
UI_COMMAND( MoveSelectionToTop2DLayer, "Bring selection to the front snap layer", "Bring selection to the front snap layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageUp, EModifierKey::Shift | EModifierKey::Control) );
|
|
UI_COMMAND( MoveSelectionToBottom2DLayer, "Send selection to the back snap layer", "Send selection to the back snap layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageDown, EModifierKey::Shift | EModifierKey::Control) );
|
|
UI_COMMAND( Select2DLayerAbove, "Select next 2D layer", "Changes the active layer to the next 2D layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageUp, EModifierKey::Alt) );
|
|
UI_COMMAND( Select2DLayerBelow, "Select previous 2D layer", "Changes the active layer to the previous 2D layer", EUserInterfaceActionType::Button, FInputChord(EKeys::PageDown, EModifierKey::Alt) );
|
|
|
|
|
|
UI_COMMAND( SnapToFloor, "Snap to Floor", "Snaps the actor or component to the floor below it", EUserInterfaceActionType::Button, FInputChord( EKeys::End ) );
|
|
UI_COMMAND( AlignToFloor, "Align to Floor", "Aligns the actor or component with the floor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapPivotToFloor, "Snap Pivot to Floor", "Snaps the actor to the floor at its pivot point", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Alt, EKeys::End ) );
|
|
UI_COMMAND( AlignPivotToFloor, "Align Pivot to Floor", "Aligns the actor with the floor at its pivot point", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapBottomCenterBoundsToFloor, "Snap Bottom Center Bounds to Floor", "Snaps the actor to the floor at its bottom center bounds", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::End ) );
|
|
UI_COMMAND( AlignBottomCenterBoundsToFloor, "Align Bottom Center Bounds to Floor", "Aligns the actor with the floor at its bottom center bounds", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapOriginToActor, "Snap Origin to Actor", "SNaps the actor to another actor at its origin", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AlignOriginToActor, "Align Origin to Actor", "Aligns the actor to another actor at its origin", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapToActor, "Snap to Actor", "Snaps the actor to another actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AlignToActor, "Align to Actor", "Aligns the actor with another actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapPivotToActor, "Snap Pivot to Actor", "Snaps the actor to another actor at its pivot point", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AlignPivotToActor, "Align Pivot to Actor", "Aligns the actor with another actor at its pivot point", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SnapBottomCenterBoundsToActor, "Snap Bottom Center Bounds to Actor", "Snaps the actor to another actor at its bottom center bounds", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AlignBottomCenterBoundsToActor, "Align Bottom Center Bounds to Actor", "Aligns the actor with another actor at its bottom center bounds", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( DeltaTransformToActors, "Delta Transform", "Apply Delta Transform to selected actors", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MirrorActorX, "Mirror X", "Mirrors the actor along the X axis", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MirrorActorY, "Mirror Y", "Mirrors the actor along the Y axis", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MirrorActorZ, "Mirror Z", "Mirrors the actor along the Z axis", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( LockActorMovement, "Lock Actor Movement", "Locks the actor so it cannot be moved", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( DetachFromParent, "Detach", "Detach the actor from its parent", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AttachSelectedActors, "Attach Selected Actors", "Attach the selected actors to the last selected actor", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Alt, EKeys::B) );
|
|
UI_COMMAND( AttachActorIteractive, "Attach Actor Interactive", "Start an interactive actor picker to let you choose a parent for the currently selected actor", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Alt, EKeys::A) );
|
|
UI_COMMAND( CreateNewOutlinerFolder, "Create Folder", "Place the selected actors in a new folder", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( HoldToEnableVertexSnapping, "Hold to Enable Vertex Snapping", "When the key binding is pressed and held vertex snapping will be enabled", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::V) );
|
|
|
|
//@ todo Slate better tooltips for pivot options
|
|
UI_COMMAND( SavePivotToPrePivot, "Set as Pivot Offset", "Sets the current pivot location as the pivot offset for this actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ResetPrePivot, "Reset Pivot Offset", "Resets the pivot offset for this actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ResetPivot, "Reset Pivot", "Resets the pivot", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MovePivotHere, "Set Pivot Offset Here", "Sets the pivot offset to the clicked location", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MovePivotHereSnapped, "Set Pivot Offset Here (Snapped)", "Sets the pivot offset to the nearest grid point to the clicked location", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MovePivotToCenter, "Center on Selection", "Centers the pivot to the middle of the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( ConvertToAdditive, "Additive", "Converts the selected brushes to additive brushes", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ConvertToSubtractive, "Subtractive", "Converts the selected brushes to subtractive brushes", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( OrderFirst, "To First", "Changes the drawing order of the selected brushes so they are the first to draw", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( OrderLast, "To Last", "Changes the drawing order of the selected brushes so they are the last to draw", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( MakeSolid, "Solid", "Makes the selected brushes solid", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MakeSemiSolid, "Semi-Solid", "Makes the selected brushes semi-solid", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( MakeNonSolid, "Non-Solid", "Makes the selected brushes non-solid", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( MergePolys, "Merge", "Merges multiple polygons on a brush face into as few as possible", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SeparatePolys, "Separate", "Reverses the effect of a previous merge", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
// RegroupActors uses GroupActors for it's label and tooltip when simply grouping a selection of actors using overrides. This is to provide display of the chord which is the same for both.
|
|
UI_COMMAND( GroupActors, "Group", "Groups the selected actors", EUserInterfaceActionType::Button, FInputChord( /*EKeys::G, EModifierKey::Control*/ ) );
|
|
UI_COMMAND( RegroupActors, "Regroup", "Regroups the selected actors into a new group, removing any current groups in the selection", EUserInterfaceActionType::Button, FInputChord( EKeys::G, EModifierKey::Control ) );
|
|
UI_COMMAND( UngroupActors, "Ungroup", "Ungroups the selected actors", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::G ) );
|
|
UI_COMMAND( AddActorsToGroup, "Add to Group", "Adds the selected actors to the selected group", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( RemoveActorsFromGroup, "Remove from Group", "Removes the selected actors from the selected groups", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( LockGroup, "Lock", "Locks the selected groups", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( UnlockGroup, "Unlock", "Unlocks the selected groups", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
#if PLATFORM_MAC
|
|
UI_COMMAND( ShowAll, "Show All Actors", "Shows all actors", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Command, EKeys::H ) );
|
|
#else
|
|
UI_COMMAND( ShowAll, "Show All Actors", "Shows all actors", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::H ) );
|
|
#endif
|
|
UI_COMMAND( ShowSelectedOnly, "Show Only Selected", "Shows only the selected actors", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ShowSelected, "Show Selected", "Shows the selected actors", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::H ) );
|
|
UI_COMMAND( HideSelected, "Hide Selected", "Hides the selected actors", EUserInterfaceActionType::Button, FInputChord( EKeys::H ) );
|
|
UI_COMMAND( ShowAllStartup, "Show All At Startup", "Shows all actors at startup", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ShowSelectedStartup, "Show Selected At Startup", "Shows selected actors at startup", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( HideSelectedStartup, "Hide Selected At Startup", "Hide selected actors at startup", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CycleNavigationDataDrawn, "Cycle Navigation Data Drawn", "Cycles through navigation data (navmeshes for example) to draw one at a time", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Alt, EKeys::N ) );
|
|
|
|
UI_COMMAND( SelectNone, "Unselect All", "Unselects all actors", EUserInterfaceActionType::Button, FInputChord( EKeys::Escape ) ) ;
|
|
UI_COMMAND( InvertSelection, "Invert Selection", "Inverts the current selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( SelectAllActorsOfSameClass, "Select All Actors of Same Class", "Selects all the actors that have the same class", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift|EModifierKey::Control, EKeys::A) );
|
|
UI_COMMAND( SelectAllActorsOfSameClassWithArchetype, "Select All Actors with Same Archetype", "Selects all the actors of the same class that have the same archetype", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectComponentOwnerActor, "Select Component Owner", "Select the actor that owns the currently selected component(s)", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectRelevantLights, "Select Relevant Lights", "Select all lights relevant to the current selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectStaticMeshesOfSameClass, "Select All Using Selected Static Meshes (Selected Actor Types)", "Selects all actors with the same static mesh and actor class as the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectOwningHierarchicalLODCluster, "Select Owning Hierarchical LOD cluster Using Selected Static Mesh (Selected Actor Types)", "Select Owning Hierarchical LOD cluster for the selected actor", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND( SelectStaticMeshesAllClasses, "Select All Using Selected Static Meshes (All Actor Types)", "Selects all actors with the same static mesh as the selection", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::E ) );
|
|
UI_COMMAND( SelectSkeletalMeshesOfSameClass, "Select All Using Selected Skeletal Meshes (Selected Actor Types)", "Selects all actors with the same skeletal mesh and actor class as the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectSkeletalMeshesAllClasses, "Select All Using Selected Skeletal Meshes (All Actor Types)", "Selects all actors with the same skeletal mesh as the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectAllWithSameMaterial, "Select All With Same Material", "Selects all actors with the same material as the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectMatchingEmitter, "Select All Matching Emitters", "Selects all emitters with the same particle system as the selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectAllLights, "Select All Lights", "Selects all lights", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectStationaryLightsExceedingOverlap, "Select Stationary Lights exceeding overlap", "Selects all stationary lights exceeding the overlap limit", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectAllAddditiveBrushes, "Select All Additive Brushes", "Selects all additive brushes", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectAllSubtractiveBrushes, "Select All Subtractive Brushes", "Selects all subtractive brushes", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SelectAllActorsControlledByMatinee, "Select Actors Used by This Matinee", "Selects all actors controlled by this Matinee", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( SelectAllSurfaces, "Select All Surfaces", "Selects all bsp surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::S) );
|
|
|
|
UI_COMMAND( SurfSelectAllMatchingBrush, "Select Matching Brush", "Selects the surfaces belonging to the same brush as the selected surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::B) );
|
|
UI_COMMAND( SurfSelectAllMatchingTexture, "Select Matching Material", "Selects all surfaces with the same material as the selected surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::T) );
|
|
UI_COMMAND( SurfSelectAllAdjacents, "Select All Adjacent Surfaces", "Selects all surfaces adjacent to the currently selected surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::J) );
|
|
UI_COMMAND( SurfSelectAllAdjacentCoplanars, "Select All Coplanar Surfaces", "Selects all surfaces adjacent and coplanar with the selected surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::C) );
|
|
UI_COMMAND( SurfSelectAllAdjacentWalls, "Select All Adjacent Wall Surfaces", "Selects all adjacent upright surfaces", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::W) );
|
|
UI_COMMAND( SurfSelectAllAdjacentFloors, "Select All Adjacent Floor Surfaces", "Selects all adjacent floor sufaces(ones with normals pointing up)", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::U) );
|
|
UI_COMMAND( SurfSelectAllAdjacentSlants, "Select All Adjacent Slant Surfaces", "Selects all adjacent slant surfaces (surfaces that are not walls, floors, or ceilings according to their normals) to the currently selected surfaces.", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::Y) );
|
|
UI_COMMAND( SurfSelectReverse, "Invert Surface Selection", "Inverts the current surface selection", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::Q) );
|
|
UI_COMMAND( SurfSelectMemorize, "Memorize Surface Selection", "Stores the current surface selection in memory", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::M) );
|
|
UI_COMMAND( SurfSelectRecall, "Recall Surface Selection", "Replace the current selection with the selection saved in memory", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::R) );
|
|
UI_COMMAND( SurfSelectOr, "Surface Selection OR", "Replace the current selection with only the surfaces which are both currently selected and contained within the saved selection in memory", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::O) );
|
|
UI_COMMAND( SurfSelectAnd, "Surface Selection AND", "Add the selection of surfaces saved in memory to the current selection", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::A) );
|
|
UI_COMMAND( SurfSelectXor, "Surace Selection XOR", " Replace the current selection with only the surfaces that are not in both the current selection and the selection saved in memory", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Shift, EKeys::X) );
|
|
UI_COMMAND( SurfUnalign, "Align Surface Default", "Default surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SurfAlignPlanarAuto, "Align Surface Planar", "Planar surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SurfAlignPlanarWall, "Align Surface Planar Wall", "Planar wall surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SurfAlignPlanarFloor, "Align Surface Planar Floor", "Planar floor surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SurfAlignBox, "Align Surface Box", "Box surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( SurfAlignFit, "Align Surface Fit", "Best fit surface alignment", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ApplyMaterialToSurface, "Apply Material to Surface Selection", "Applies the selected material to the selected surfaces", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( CreateBoundingBoxVolume, "Create Bounding Box Blocking Volume From Mesh", "Create a bounding box blocking volume from the static mesh", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CreateHeavyConvexVolume, "Heavy Convex Blocking Volume From Mesh", "Creates a heavy convex blocking volume from the static mesh", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CreateNormalConvexVolume, "Normal Convex Blocking Volume From Mesh", "Creates a normal convex blocking volume from the static mesh", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CreateLightConvexVolume, "Light Convex Blocking Volume From Mesh", "Creates a light convex blocking volume from the static mesh", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CreateRoughConvexVolume, "Rought Convex Blocking Volume From Mesh", "Creates a rough convex blocking volume from the static mesh", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( KeepSimulationChanges, "Keep Simulation Changes", "Saves the changes made to this actor in Simulate mode to the actor's default state.", EUserInterfaceActionType::Button, FInputChord( EKeys::K ) );
|
|
|
|
UI_COMMAND( MakeActorLevelCurrent, "Make Selected Actor's Level Current", "Makes the selected actor's level the current level", EUserInterfaceActionType::Button, FInputChord( EKeys::M ) );
|
|
#if PLATFORM_MAC
|
|
UI_COMMAND( MoveSelectedToCurrentLevel, "Move Selection to Current Level", "Moves the selected actors to the current level", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Command, EKeys::M ) );
|
|
#else
|
|
UI_COMMAND( MoveSelectedToCurrentLevel, "Move Selection to Current Level", "Moves the selected actors to the current level", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::M ) );
|
|
#endif
|
|
UI_COMMAND( FindActorLevelInContentBrowser, "Find Actor Level in Content Browser", "Finds the selected actors' level in the content browser", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( FindLevelsInLevelBrowser, "Find Levels in Level Browser", "Finds the selected actors' levels in the level browser", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AddLevelsToSelection, "Add Levels to Selection", "Adds the selected actors' levels to the current level browser selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( RemoveLevelsFromSelection, "Remove Levels from Selection", "Removes the selected actors' levels from the current level browser selection", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( FindActorInLevelScript, "Find in Level Blueprint", "Finds any references to the selected actor in its level's blueprint", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( WorldProperties, "World Settings", "Displays the world settings", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( OpenContentBrowser, "Open Content Browser", "Opens the Content Browser", EUserInterfaceActionType::Button, FInputChord(EModifierKey::Control|EModifierKey::Shift, EKeys::F) );
|
|
UI_COMMAND( OpenMarketplace, "Open Marketplace", "Opens the Marketplace", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( AddMatinee, "Add Matinee [Legacy]", "Creates a new matinee actor to edit", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( EditMatinee, "Edit Matinee", "Selects a Matinee to edit", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( ToggleVR, "Toggle VR", "Toggles VR (Virtual Reality) mode", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Alt, EKeys::V ) );
|
|
|
|
UI_COMMAND( OpenLevelBlueprint, "Open Level Blueprint", "Edit the Level Blueprint for the current level", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CheckOutProjectSettingsConfig, "Check Out", "Checks out the project settings config file so the game mode can be set.", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( CreateBlankBlueprintClass, "New Empty Blueprint Class...", "Create a new Blueprint Class", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ConvertSelectionToBlueprintViaHarvest, "Convert Selected Components to Blueprint Class...", "Replace all of the selected actors with a new Blueprint Class based on Actor that contains the components", EUserInterfaceActionType::Button, FInputChord() );
|
|
UI_COMMAND( ConvertSelectionToBlueprintViaSubclass, "Convert Selected Actor to Blueprint Class...", "Replace the selected actor with a new Blueprint subclass based on the class of the selected Actor", EUserInterfaceActionType::Button, FInputChord() );
|
|
|
|
UI_COMMAND( ShowTransformWidget, "Show Transform Widget", "Toggles the visibility of the transform widgets", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( AllowTranslucentSelection, "Allow Translucent Selection", "Allows translucent objects to be selected", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::T) );
|
|
UI_COMMAND( AllowGroupSelection, "Allow Group Selection", "Allows actor groups to be selected", EUserInterfaceActionType::ToggleButton, FInputChord(EModifierKey::Control|EModifierKey::Shift, EKeys::G) );
|
|
UI_COMMAND( StrictBoxSelect, "Strict Box Selection", "When enabled an object must be entirely encompassed by the selection box when marquee box selecting", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( TransparentBoxSelect, "Box Select Occluded Objects", "When enabled, marquee box select operations will also select objects that are occluded by other objects.", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( DrawBrushMarkerPolys, "Draw Brush Polys", "Draws semi-transparent polygons around a brush when selected", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( OnlyLoadVisibleInPIE, "Only Load Visible Levels in Game Preview", "If enabled, when game preview starts, only visible levels will be loaded", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleSocketSnapping, "Enable Socket Snapping", "Enables or disables snapping to sockets", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleParticleSystemLOD, "Enable Particle System LOD Switching", "If enabled particle systems will use distance LOD switching in perspective viewports", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleFreezeParticleSimulation, "Freeze Particle Simulation", "If enabled particle systems will freeze their simulation state", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleParticleSystemHelpers, "Toggle Particle System Helpers", "Toggles showing particle system helper widgets in viewports", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleLODViewLocking, "Enable LOD View Locking", "If enabled viewports of the same type will use the same LOD", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( LevelStreamingVolumePrevis, "Enable Automatic Level Streaming", "If enabled, the viewport will stream in levels automatically when the camera is moved", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( EnableActorSnap, "Enable Actor Snapping", "If enabled, actors will snap to the location of other actors when they are within distance", EUserInterfaceActionType::ToggleButton, FInputChord(EModifierKey::Control|EModifierKey::Shift, EKeys::K) );
|
|
UI_COMMAND( EnableVertexSnap, "Enable Vertex Snapping","If enabled, actors will snap to the location of the nearest vertex on another actor in the direction of movement", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
UI_COMMAND( ToggleHideViewportUI, "Hide Viewport UI", "Toggles hidden viewport UI mode. Hides all overlaid viewport UI widgets", EUserInterfaceActionType::ToggleButton, FInputChord() );
|
|
|
|
//if (FParse::Param( FCommandLine::Get(), TEXT( "editortoolbox" ) ))
|
|
//{
|
|
// UI_COMMAND( BspMode, "Enable Bsp Mode", "Enables BSP mode", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Shift, EKeys::One ) );
|
|
// UI_COMMAND( MeshPaintMode, "Enable Mesh Paint Mode", "Enables mesh paint mode", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Shift, EKeys::Two ) );
|
|
// UI_COMMAND( LandscapeMode, "Enable Landscape Mode", "Enables landscape editing", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Shift, EKeys::Three ) );
|
|
// UI_COMMAND( FoliageMode, "Enable Foliage Mode", "Enables foliage editing", EUserInterfaceActionType::ToggleButton, FInputChord( EModifierKey::Shift, EKeys::Four ) );
|
|
//}
|
|
|
|
UI_COMMAND( ShowSelectedDetails, "Show Actor Details", "Opens a details panel for the selected actors", EUserInterfaceActionType::Button, FInputChord( EKeys::F4 ) );
|
|
|
|
UI_COMMAND( RecompileShaders, "Recompile Changed Shaders", "Recompiles shaders which are out of date", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift|EModifierKey::Control, EKeys::Period ) );
|
|
UI_COMMAND( ProfileGPU, "Profile GPU", "Profiles the GPU for the next frame and opens a window with profiled data", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift|EModifierKey::Control, EKeys::Comma ) );
|
|
|
|
UI_COMMAND( ResetAllParticleSystems, "Reset All Particle Systems", "Resets all particle system emitters (removes all active particles and restarts them)", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Shift, EKeys::Slash ) );
|
|
UI_COMMAND( ResetSelectedParticleSystem, "Resets Selected Particle Systems" , "Resets selected particle system emitters (removes all active particles and restarts them)", EUserInterfaceActionType::Button, FInputChord( EKeys::Slash ) );
|
|
|
|
UI_COMMAND( SelectActorsInLayers, "Select all actors in selected actor's layers", "Selects all actors belonging to the layers of the currently selected actors", EUserInterfaceActionType::Button, FInputChord( EModifierKey::Control, EKeys::L ) );
|
|
|
|
UI_COMMAND( FocusAllViewportsToSelection, "Focus Selected Actors in All Viewports", "Moves the camera in front of the selected actors in all open viewports", EUserInterfaceActionType::Button, FInputChord( EKeys::F, EModifierKey::Shift ) );
|
|
|
|
UI_COMMAND(MaterialQualityLevel_Low, "Low", "Sets material quality in the scene to low.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(MaterialQualityLevel_Medium, "Medium", "Sets material quality in the scene to medium.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(MaterialQualityLevel_High, "High", "Sets material quality in the scene to high.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
|
|
UI_COMMAND(PreviewPlatformOverride_DefaultES2, "Default Mobile / HTML5 Preview", "Use default mobile settings (no quality overrides).", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(PreviewPlatformOverride_AndroidGLES2, "Android Preview", "Mobile preview using Android's quality settings.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
|
|
UI_COMMAND(PreviewPlatformOverride_DefaultES31, "Default High-End Mobile", "Use default mobile settings (no quality overrides).", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(PreviewPlatformOverride_AndroidGLES31, "Android GLES3.1 Preview", "Mobile preview using Android ES3.1 quality settings.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(PreviewPlatformOverride_AndroidVulkanES31, "Android Vulkan Preview", "Mobile preview using Android Vulkan quality settings.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
UI_COMMAND(PreviewPlatformOverride_IOSMetalES31, "iOS Preview", "Mobile preview using iOS material quality settings.", EUserInterfaceActionType::RadioButton, FInputChord());
|
|
|
|
|
|
UI_COMMAND( ConnectToSourceControl, "Connect to Source Control...", "Opens a dialog to connect to source control.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND( ChangeSourceControlSettings, "Change Source Control Settings...", "Opens a dialog to change source control settings.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND( CheckOutModifiedFiles, "Check Out Modified Files...", "Opens a dialog to check out any assets which have been modified.", EUserInterfaceActionType::Button, FInputChord());
|
|
UI_COMMAND( SubmitToSourceControl, "Submit to Source Control...", "Opens a dialog with check in options for content and levels.", EUserInterfaceActionType::Button, FInputChord());
|
|
|
|
static const FText FeatureLevelLabels[ERHIFeatureLevel::Num] =
|
|
{
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewType_ES2", "Mobile / HTML5"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewType_ES31", "High-End Mobile"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewType_SM4", "Shader Model 4"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewType_SM5", "Shader Model 5"),
|
|
};
|
|
|
|
static const FText FeatureLevelToolTips[ERHIFeatureLevel::Num] =
|
|
{
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewTooltip_ES2", "OpenGLES 2"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewTooltip_ES3", "OpenGLES 3.1, Metal, Vulkan"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewTooltip_SM4", "DirectX 10, OpenGL 3.3+"),
|
|
NSLOCTEXT("LevelEditorCommands", "FeatureLevelPreviewTooltip_SM5", "DirectX 11, OpenGL 4.3+, PS4, XB1"),
|
|
};
|
|
|
|
for (int32 i = 0; i < ERHIFeatureLevel::Num; ++i)
|
|
{
|
|
FName Name;
|
|
GetFeatureLevelName((ERHIFeatureLevel::Type)i, Name);
|
|
|
|
FeatureLevelPreview[i] =
|
|
FUICommandInfoDecl(
|
|
this->AsShared(),
|
|
Name,
|
|
FeatureLevelLabels[i],
|
|
FeatureLevelToolTips[i])
|
|
.UserInterfaceType(EUserInterfaceActionType::RadioButton)
|
|
.DefaultChord(FInputChord());
|
|
}
|
|
|
|
UI_COMMAND(OpenMergeActor, "Merge Actors", "Opens the Merge Actor panel", EUserInterfaceActionType::Button, FInputChord());
|
|
}
|
|
|
|
PRAGMA_ENABLE_OPTIMIZATION
|
|
|
|
#undef LOCTEXT_NAMESPACE
|