2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "StaticMeshComponentDetails.h"
2016-11-23 15:48:37 -05:00
# include "Components/StaticMeshComponent.h"
# include "PropertyHandle.h"
# include "DetailLayoutBuilder.h"
2018-01-20 11:19:29 -05:00
# include "Widgets/Input/SNumericEntryBox.h"
# include "Widgets/Layout/SWidgetSwitcher.h"
2016-12-09 17:27:23 -05:00
# include "IDetailPropertyRow.h"
# include "DetailCategoryBuilder.h"
# include "DetailWidgetRow.h"
2016-12-12 01:33:44 -05:00
# include "Engine/StaticMesh.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "StaticMeshComponentDetails"
TSharedRef < IDetailCustomization > FStaticMeshComponentDetails : : MakeInstance ( )
{
return MakeShareable ( new FStaticMeshComponentDetails ) ;
}
2016-12-09 15:05:28 -05:00
void FStaticMeshComponentDetails : : CustomizeDetails ( IDetailLayoutBuilder & DetailBuilder )
2014-03-14 14:13:41 -04:00
{
// Create a category so this is displayed early in the properties
2016-12-09 15:05:28 -05:00
DetailBuilder . EditCategory ( " StaticMesh " , FText : : GetEmpty ( ) , ECategoryPriority : : Important ) ;
2016-05-19 19:35:35 -04:00
TSharedRef < IPropertyHandle > UseDefaultCollision = DetailBuilder . GetProperty ( GET_MEMBER_NAME_CHECKED ( UStaticMeshComponent , bUseDefaultCollision ) ) ;
UseDefaultCollision - > MarkHiddenByCustomization ( ) ;
2016-12-09 15:05:28 -05:00
IDetailCategoryBuilder & LightingCategory = DetailBuilder . EditCategory ( " Lighting " ) ;
// Store off the properties for analysis in later function calls.
OverrideLightResProperty = DetailBuilder . GetProperty ( GET_MEMBER_NAME_CHECKED ( UStaticMeshComponent , OverriddenLightMapRes ) ) ;
// Add the row that we will be customizing below.
IDetailPropertyRow & OverrideLightResRow = LightingCategory . AddProperty ( OverrideLightResProperty ) ;
// Create the default property value widget, we'll use this in certain circumstances outlined below.
TSharedRef < SWidget > ValueWidget = OverrideLightResProperty - > CreatePropertyValueWidget ( ) ;
// Store off the objects that we are editing for analysis in later function calls.
DetailBuilder . GetObjectsBeingCustomized ( ObjectsCustomized ) ;
// We use similar logic here to where it is ultimately used:
// UStaticMeshComponent::GetLightMapResolution
// If there is a static mesh and the override is enabled, use the real value of the property.
// If there is a static mesh and the override is disabled, use the static mesh's resolution value.
// If no static mesh is assigned, use 0.
// Ultimately, the last case is an error and we need to warn the user. We also need to handle multiple selection appropriately,
// thus the widget switcher below.
OverrideLightResRow . CustomWidget ( )
. NameContent ( )
[
// Use the default lightmap property name
OverrideLightResProperty - > CreatePropertyNameWidget ( )
]
. ValueContent ( )
2021-09-16 16:23:57 -04:00
. VAlign ( VAlign_Center )
2016-12-09 15:05:28 -05:00
[
SNew ( SWidgetSwitcher )
. WidgetIndex ( this , & FStaticMeshComponentDetails : : HandleNoticeSwitcherWidgetIndex )
+ SWidgetSwitcher : : Slot ( ) // Slot 0, the single common value for static mesh lightmap resolutions.
[
SNew ( SNumericEntryBox < int32 > )
. ToolTipText ( OverrideLightResProperty - > GetToolTipText ( ) )
. IsEnabled ( false )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Value ( this , & FStaticMeshComponentDetails : : GetStaticMeshLightResValue )
]
+ SWidgetSwitcher : : Slot ( ) // Slot 1, the editor for when overrides are enabled
[
ValueWidget
]
+ SWidgetSwitcher : : Slot ( ) // Slot 2, the editor for when we are missing one or more static meshes.
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. ToolTipText ( OverrideLightResProperty - > GetToolTipText ( ) )
. IsEnabled ( false )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( LOCTEXT ( " DetailsMissingStaticMesh " , " Missing StaticMesh! " ) )
]
+ SWidgetSwitcher : : Slot ( ) // Slot 3, the editor for when we have multiple heterogenous values.
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. ToolTipText ( OverrideLightResProperty - > GetToolTipText ( ) )
. IsEnabled ( false )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
. Text ( LOCTEXT ( " DetailsMultipleValues " , " Multiple Values " ) )
]
] ;
}
TOptional < int32 > FStaticMeshComponentDetails : : GetStaticMeshLightResValue ( ) const
{
// Go ahead and grab the current value for the static mesh resolution as this shouldn't change during the lifetime
// of this customization.
TOptional < int32 > DefaultResolution = 0 ;
for ( int32 i = 0 ; i < ObjectsCustomized . Num ( ) & & DefaultResolution = = 0 ; i + + )
{
UStaticMeshComponent * Component = Cast < UStaticMeshComponent > ( ObjectsCustomized [ i ] . Get ( ) ) ;
if ( Component ! = nullptr & & Component - > GetStaticMesh ( ) ! = nullptr )
{
2020-10-28 22:08:44 -04:00
DefaultResolution = Component - > GetStaticMesh ( ) - > GetLightMapResolution ( ) ;
2016-12-09 15:05:28 -05:00
}
}
return DefaultResolution ;
}
int FStaticMeshComponentDetails : : HandleNoticeSwitcherWidgetIndex ( ) const
{
// Determine if the override enabled is set homogenously or not.
bool bOverrideEnabled = false ;
FPropertyAccess : : Result AccessResultOverrideEnabled = FPropertyAccess : : Fail ;
bool bOverrideFound = false ;
// Loop through all the components being edited to see if any are missing static meshes
// and to see if their lightmap resolutions are all the same on those static meshes.
FPropertyAccess : : Result AccessResultOverride = FPropertyAccess : : Success ;
bool bHasMissingStaticMeshes = false ;
int32 OverrideLightRes = - 1 ;
check ( ObjectsCustomized . Num ( ) > 0 ) ;
for ( int32 i = 0 ; i < ObjectsCustomized . Num ( ) ; i + + )
{
UStaticMeshComponent * Component = Cast < UStaticMeshComponent > ( ObjectsCustomized [ i ] . Get ( ) ) ;
if ( Component ! = nullptr )
{
if ( Component - > GetStaticMesh ( ) = = nullptr )
{
bHasMissingStaticMeshes = true ;
AccessResultOverride = FPropertyAccess : : MultipleValues ;
}
else
{
if ( bOverrideFound = = false )
{
AccessResultOverrideEnabled = FPropertyAccess : : Success ;
bOverrideEnabled = Component - > bOverrideLightMapRes ;
bOverrideFound = true ;
}
else if ( bOverrideEnabled ! = Component - > bOverrideLightMapRes )
{
AccessResultOverrideEnabled = FPropertyAccess : : MultipleValues ;
}
2020-10-28 22:08:44 -04:00
int32 CurrentStaticLightRes = Component - > GetStaticMesh ( ) - > GetLightMapResolution ( ) ;
2016-12-09 15:05:28 -05:00
if ( OverrideLightRes = = - 1 )
{
OverrideLightRes = CurrentStaticLightRes ;
}
else if ( CurrentStaticLightRes ! = OverrideLightRes )
{
AccessResultOverride = FPropertyAccess : : MultipleValues ;
}
}
}
}
// This gets a little hairy. The desired behavior is as follows:
// For single item selection:
// a) if override is enabled and we have a valid static mesh, display the general editor for the property.
// b) if override is disabled and we have a valid static mesh, display the static mesh's value for the property.
// c) otherwise, warn the user if they are missing the static mesh.
// For multiple selection:
// d) if all overrides are enabled, all have valid meshes, and all have the same value, display the general editor.
// e) if all overrides are enabled, all have valid meshes, and all have different values, display the general editor (which should say Multiple Values).
// f) if all overrides are disabled, all have valid meshes, and all static meshes have the same value for the resolution, display that common resolution
// g) if all overrides are disabled, all have valid meshes, and all static meshes have heterogenous values for the resolution, display the multiple values read-only text.
// h) if overrides are heterogenous, display the multiple values read-only text.
// i) if any of the above have invalid static meshes, warn the user.
if ( bHasMissingStaticMeshes ) // Covers cases c and i above.
{
return 2 ;
}
else if ( AccessResultOverrideEnabled = = FPropertyAccess : : MultipleValues ) // covers case h above
{
return 3 ;
}
else if ( AccessResultOverride = = FPropertyAccess : : MultipleValues & & bOverrideEnabled = = false ) // covers case g above
{
return 3 ;
}
else if ( bOverrideEnabled = = false ) // covers cases b and f above
{
return 0 ;
}
else // covers cases a, d, and e above
{
return 1 ;
}
2016-02-04 10:55:30 -05:00
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE