Files
UnrealEngineUWP/Engine/Source/Editor/DetailCustomizations/Private/MathStructCustomizations.cpp
Max Preussner f167dce37e Slate: Moved TestSuite and ColorPicker into new module AppFramework
The AppFramework module is intended to be used for compound widgets and UI related classes that are too specific (not basic enough) for Slate, but also not Editor specific (reusable in non-Editor applications and games). The test suite has been moved in its entirety for now, but core widget specific test classes will eventually be split off and moved back into Slate, so that they can live alongside of their corresponding widgets.

Other changes:
- moved to "include what you use" scheme for SColorPicker
- broke out color picker related widgets that may be reusable
- added forward declarations to reduce header include dependencies

#CodeReview: saul.abreu

[CL 2275496 by Max Preussner in Main branch]
2014-08-27 20:35:19 -04:00

698 lines
23 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "DetailCustomizationsPrivatePCH.h"
#include "Materials/MaterialExpressionConstant3Vector.h"
#include "MathStructCustomizations.h"
#include "IPropertyUtilities.h"
#include "SColorPicker.h"
#define LOCTEXT_NAMESPACE "FMathStructCustomization"
TSharedRef<IPropertyTypeCustomization> FMathStructCustomization::MakeInstance()
{
return MakeShareable( new FMathStructCustomization );
}
void FMathStructCustomization::CustomizeHeader( TSharedRef<class IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
{
GetSortedChildren( StructPropertyHandle, SortedChildHandles );
MakeHeaderRow( StructPropertyHandle, HeaderRow );
}
void FMathStructCustomization::CustomizeChildren( TSharedRef<class IPropertyHandle> StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
{
for( int32 ChildIndex = 0; ChildIndex < SortedChildHandles.Num(); ++ChildIndex )
{
TSharedRef<IPropertyHandle> ChildHandle = SortedChildHandles[ChildIndex];
// Add the individual properties as children as well so the vector can be expanded for more room
StructBuilder.AddChildProperty( ChildHandle );
}
}
void FMathStructCustomization::MakeHeaderRow( TSharedRef<class IPropertyHandle>& StructPropertyHandle, FDetailWidgetRow& Row )
{
// We'll set up reset to default ourselves
const bool bDisplayResetToDefault = false;
const FString DisplayNameOverride = TEXT("");
TWeakPtr<IPropertyHandle> StructWeakHandlePtr = StructPropertyHandle;
TSharedPtr<SHorizontalBox> HorizontalBox;
Row.NameContent()
[
StructPropertyHandle->CreatePropertyNameWidget( DisplayNameOverride, bDisplayResetToDefault )
]
.ValueContent()
// Make enough space for each child handle
.MinDesiredWidth(125.0f * SortedChildHandles.Num() )
.MaxDesiredWidth(125.0f * SortedChildHandles.Num() )
[
SAssignNew( HorizontalBox, SHorizontalBox )
.IsEnabled( this, &FMathStructCustomization::IsValueEnabled, StructWeakHandlePtr )
];
for( int32 ChildIndex = 0; ChildIndex < SortedChildHandles.Num(); ++ChildIndex )
{
TSharedRef<IPropertyHandle> ChildHandle = SortedChildHandles[ChildIndex];
const bool bLastChild = SortedChildHandles.Num()-1 == ChildIndex;
// Make a widget for each property. The vector component properties will be displayed in the header
HorizontalBox->AddSlot()
.Padding( FMargin(0.0f, 2.0f, bLastChild ? 0.0f : 3.0f, 2.0f ) )
[
MakeChildWidget( ChildHandle )
];
}
if ( StructPropertyHandle->GetProperty()->HasMetaData("AllowPreserveRatio") )
{
if ( !GConfig->GetBool(TEXT("SelectionDetails"), *(StructPropertyHandle->GetProperty()->GetName() + TEXT("_PreserveScaleRatio")), bPreserveScaleRatio, GEditorUserSettingsIni) )
{
bPreserveScaleRatio = true;
}
HorizontalBox->AddSlot()
.AutoWidth()
.MaxWidth( 18.0f )
[
// Add a checkbox to toggle between preserving the ratio of x,y,z components of scale when a value is entered
SNew( SCheckBox )
.IsChecked(this, &FMathStructCustomization::IsPreserveScaleRatioChecked)
.OnCheckStateChanged(this, &FMathStructCustomization::OnPreserveScaleRatioToggled, StructWeakHandlePtr)
.Style( FEditorStyle::Get(), "TransparentCheckBox" )
.ToolTipText( LOCTEXT("PreserveScaleToolTip", "When locked, scales uniformly based on the current xyz scale values so the object maintains its shape in each direction when scaled" ) )
[
SNew( SImage )
.Image(this, &FMathStructCustomization::GetPreserveScaleRatioImage)
.ColorAndOpacity( FSlateColor::UseForeground() )
]
];
}
}
const FSlateBrush* FMathStructCustomization::GetPreserveScaleRatioImage() const
{
return bPreserveScaleRatio ? FEditorStyle::GetBrush(TEXT("GenericLock")) : FEditorStyle::GetBrush(TEXT("GenericUnlock"));
}
ESlateCheckBoxState::Type FMathStructCustomization::IsPreserveScaleRatioChecked() const
{
return bPreserveScaleRatio ? ESlateCheckBoxState::Checked : ESlateCheckBoxState::Unchecked;
}
void FMathStructCustomization::OnPreserveScaleRatioToggled(ESlateCheckBoxState::Type NewState, TWeakPtr<IPropertyHandle> PropertyHandle)
{
bPreserveScaleRatio = ( NewState == ESlateCheckBoxState::Checked ) ? true : false;
if ( PropertyHandle.IsValid() )
{
FString SettingKey = ( PropertyHandle.Pin()->GetProperty()->GetName() + TEXT("_PreserveScaleRatio") );
GConfig->SetBool(TEXT("SelectionDetails"), *SettingKey, bPreserveScaleRatio, GEditorUserSettingsIni);
}
}
void FMathStructCustomization::GetSortedChildren( TSharedRef<IPropertyHandle> StructPropertyHandle, TArray< TSharedRef<IPropertyHandle> >& OutChildren )
{
OutChildren.Empty();
uint32 NumChildren;
StructPropertyHandle->GetNumChildren( NumChildren );
for( uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex )
{
OutChildren.Add( StructPropertyHandle->GetChildHandle( ChildIndex ).ToSharedRef() );
}
}
template<typename NumericType>
TSharedRef<SWidget> FMathStructCustomization::MakeNumericWidget(TSharedRef<IPropertyHandle>& PropertyHandle)
{
TWeakPtr<IPropertyHandle> WeakHandlePtr = PropertyHandle;
return
SNew( SNumericEntryBox<NumericType> )
.IsEnabled( this, &FMathStructCustomization::IsValueEnabled, WeakHandlePtr )
.Value( this, &FMathStructCustomization::OnGetValue, WeakHandlePtr )
.Font( IDetailLayoutBuilder::GetDetailFont() )
.UndeterminedString( NSLOCTEXT("PropertyEditor", "MultipleValues", "Multiple Values").ToString() )
.OnValueCommitted( this, &FMathStructCustomization::OnValueCommitted<NumericType>, WeakHandlePtr )
.OnValueChanged( this, &FMathStructCustomization::OnValueChanged<NumericType>, WeakHandlePtr )
.OnBeginSliderMovement( this, &FMathStructCustomization::OnBeginSliderMovement )
.OnEndSliderMovement( this, &FMathStructCustomization::OnEndSliderMovement<NumericType> )
.LabelVAlign(VAlign_Center)
// Only allow spin on handles with one object. Otherwise it is not clear what value to spin
.AllowSpin( PropertyHandle->GetNumOuterObjects() == 1 )
.MinValue(TOptional<NumericType>())
.MaxValue(TOptional<NumericType>())
.MaxSliderValue(TOptional<NumericType>())
.MinSliderValue(TOptional<NumericType>())
.Label()
[
SNew( STextBlock )
.Font( IDetailLayoutBuilder::GetDetailFont() )
.Text( PropertyHandle->GetPropertyDisplayName() )
];
}
TSharedRef<SWidget> FMathStructCustomization::MakeChildWidget( TSharedRef<IPropertyHandle>& PropertyHandle )
{
const UClass* PropertyClass = PropertyHandle->GetPropertyClass();
if (PropertyClass == UFloatProperty::StaticClass())
{
return MakeNumericWidget<float>(PropertyHandle);
}
if (PropertyClass == UIntProperty::StaticClass())
{
return MakeNumericWidget<int32>(PropertyHandle);
}
if (PropertyClass == UByteProperty::StaticClass())
{
return MakeNumericWidget<uint8>(PropertyHandle);
}
check(0); // Unsupported class
return SNullWidget::NullWidget;
}
template<typename NumericType>
TOptional<NumericType> FMathStructCustomization::OnGetValue( TWeakPtr<IPropertyHandle> WeakHandlePtr ) const
{
NumericType NumericVal = 0;
if( WeakHandlePtr.Pin()->GetValue( NumericVal ) == FPropertyAccess::Success )
{
return TOptional<NumericType>( NumericVal );
}
// Value couldn't be accessed. Return an unset value
return TOptional<NumericType>();
}
template<typename NumericType>
void FMathStructCustomization::OnValueCommitted( NumericType NewValue, ETextCommit::Type CommitType, TWeakPtr<IPropertyHandle> WeakHandlePtr )
{
EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::DefaultFlags;
SetValue(NewValue, Flags, WeakHandlePtr);
}
template<typename NumericType>
void FMathStructCustomization::OnValueChanged( NumericType NewValue, TWeakPtr<IPropertyHandle> WeakHandlePtr )
{
if( bIsUsingSlider )
{
EPropertyValueSetFlags::Type Flags = EPropertyValueSetFlags::InteractiveChange;
SetValue(NewValue, Flags, WeakHandlePtr);
}
}
template<typename NumericType>
void FMathStructCustomization::SetValue(NumericType NewValue, EPropertyValueSetFlags::Type Flags, TWeakPtr<IPropertyHandle> WeakHandlePtr)
{
if ( bPreserveScaleRatio )
{
// Get the value for each object for the modified component
TArray<FString> OldValues;
if ( WeakHandlePtr.Pin()->GetPerObjectValues(OldValues) == FPropertyAccess::Success )
{
// Loop through each object and scale based on the new ratio for each object individually
for ( int32 OutputIndex = 0; OutputIndex < OldValues.Num(); ++OutputIndex )
{
NumericType OldValue;
TTypeFromString<NumericType>::FromString(OldValue, *OldValues[OutputIndex]);
// Account for the previous scale being zero. Just set to the new value in that case?
NumericType Ratio = OldValue == 0 ? NewValue : NewValue / OldValue;
if ( Ratio == 0 )
{
Ratio = NewValue;
}
// Loop through all the child handles (each component of the math struct, like X, Y, Z...etc)
for ( int32 ChildIndex = 0; ChildIndex < SortedChildHandles.Num(); ++ChildIndex )
{
// Ignore scaling our selves.
TSharedRef<IPropertyHandle> ChildHandle = SortedChildHandles[ChildIndex];
if ( ChildHandle != WeakHandlePtr.Pin() )
{
// Get the value for each object.
TArray<FString> ObjectChildValues;
if ( ChildHandle->GetPerObjectValues(ObjectChildValues) == FPropertyAccess::Success )
{
// Individually scale each object's components by the same ratio.
for ( int32 ChildOutputIndex = 0; ChildOutputIndex < ObjectChildValues.Num(); ++ChildOutputIndex )
{
NumericType ChildOldValue;
TTypeFromString<NumericType>::FromString(ChildOldValue, *ObjectChildValues[ChildOutputIndex]);
NumericType ChildNewValue = ChildOldValue * Ratio;
ObjectChildValues[ChildOutputIndex] = TTypeToString<NumericType>::ToSanitizedString(ChildNewValue);
}
ChildHandle->SetPerObjectValues(ObjectChildValues);
}
}
}
}
}
}
WeakHandlePtr.Pin()->SetValue(NewValue, Flags);
}
bool FMathStructCustomization::IsValueEnabled(TWeakPtr<IPropertyHandle> WeakHandlePtr) const
{
if ( WeakHandlePtr.IsValid() )
{
return !WeakHandlePtr.Pin()->IsEditConst();
}
return false;
}
void FMathStructCustomization::OnBeginSliderMovement()
{
bIsUsingSlider = true;
GEditor->BeginTransaction( NSLOCTEXT("FMathStructCustomization", "SetVectorProperty", "Set Vector Property") );
}
template<typename NumericType>
void FMathStructCustomization::OnEndSliderMovement( NumericType NewValue )
{
bIsUsingSlider = false;
GEditor->EndTransaction();
}
TSharedRef<IPropertyTypeCustomization> FRotatorStructCustomization::MakeInstance()
{
return MakeShareable( new FRotatorStructCustomization );
}
void FRotatorStructCustomization::GetSortedChildren( TSharedRef<IPropertyHandle> StructPropertyHandle, TArray< TSharedRef<IPropertyHandle> >& OutChildren )
{
static const FName Roll("Roll");
static const FName Pitch("Pitch");
static const FName Yaw("Yaw");
TSharedPtr< IPropertyHandle > RotatorChildren[3];
uint32 NumChildren;
StructPropertyHandle->GetNumChildren( NumChildren );
for( uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex )
{
TSharedRef<IPropertyHandle> ChildHandle = StructPropertyHandle->GetChildHandle( ChildIndex ).ToSharedRef();
const FName PropertyName = ChildHandle->GetProperty()->GetFName();
if( PropertyName == Roll )
{
RotatorChildren[0] = ChildHandle;
}
else if( PropertyName == Pitch )
{
RotatorChildren[1] = ChildHandle;
}
else
{
check( PropertyName == Yaw );
RotatorChildren[2] = ChildHandle;
}
}
OutChildren.Add( RotatorChildren[0].ToSharedRef() );
OutChildren.Add( RotatorChildren[1].ToSharedRef() );
OutChildren.Add( RotatorChildren[2].ToSharedRef() );
}
TSharedRef<IPropertyTypeCustomization> FColorStructCustomization::MakeInstance()
{
return MakeShareable( new FColorStructCustomization );
}
void FColorStructCustomization::CustomizeHeader( TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils )
{
TSharedPtr<FAssetThumbnailPool> Pool = StructCustomizationUtils.GetThumbnailPool();
StructPropertyHandle = InStructPropertyHandle;
bIsLinearColor = CastChecked<UStructProperty>( StructPropertyHandle->GetProperty() )->Struct->GetFName() == NAME_LinearColor;
bIgnoreAlpha = StructPropertyHandle->GetProperty()->HasMetaData(TEXT("HideAlphaChannel"));
auto PropertyUtils = StructCustomizationUtils.GetPropertyUtilities();
bDontUpdateWhileEditing = PropertyUtils.IsValid() ? PropertyUtils->DontUpdateValueWhileEditing() : false;
FMathStructCustomization::CustomizeHeader( InStructPropertyHandle, InHeaderRow, StructCustomizationUtils );
}
void FColorStructCustomization::MakeHeaderRow( TSharedRef<class IPropertyHandle>& InStructPropertyHandle, FDetailWidgetRow& Row )
{
// We'll set up reset to default ourselves
const bool bDisplayResetToDefault = false;
const FString DisplayNameOverride = TEXT("");
FSlateFontInfo NormalText = IDetailLayoutBuilder::GetDetailFont();
Row.NameContent()
[
StructPropertyHandle->CreatePropertyNameWidget( DisplayNameOverride, bDisplayResetToDefault )
]
.ValueContent()
.MinDesiredWidth(250.0f)
.MaxDesiredWidth(250.0f)
[
SNew( SHorizontalBox )
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
[
SNew( SOverlay )
+SOverlay::Slot()
[
// Displays the color with alpha unless it is ignored
SAssignNew( ColorPickerParentWidget, SColorBlock )
.Color( this, &FColorStructCustomization::OnGetColorForColorBlock )
.ShowBackgroundForAlpha(true)
.IgnoreAlpha( bIgnoreAlpha )
.OnMouseButtonDown( this, &FColorStructCustomization::OnMouseButtonDownColorBlock )
.Size( FVector2D( 35.0f, 12.0f ) )
]
+SOverlay::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew( STextBlock )
.Text(NSLOCTEXT("PropertyEditor", "MultipleValues", "Multiple Values"))
.Font(NormalText)
.ColorAndOpacity(FSlateColor(FLinearColor::Black)) // we know the background is always white, so can safely set this to black
.Visibility(this, &FColorStructCustomization::GetMultipleValuesTextVisibility)
]
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
[
// Displays the color without alpha
SNew( SColorBlock )
.Color( this, &FColorStructCustomization::OnGetColorForColorBlock )
.ShowBackgroundForAlpha(false)
.IgnoreAlpha(true)
.OnMouseButtonDown( this, &FColorStructCustomization::OnMouseButtonDownColorBlock )
.Size( FVector2D( 35.0f, 12.0f ) )
]
];
}
void FColorStructCustomization::GetSortedChildren( TSharedRef<IPropertyHandle> InStructPropertyHandle, TArray< TSharedRef<IPropertyHandle> >& OutChildren )
{
static const FName Red("R");
static const FName Green("G");
static const FName Blue("B");
static const FName Alpha("A");
// We control the order of the colors via this array so it always ends up R,G,B,A
TSharedPtr< IPropertyHandle > ColorProperties[4];
uint32 NumChildren;
InStructPropertyHandle->GetNumChildren( NumChildren );
for( uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex )
{
TSharedRef<IPropertyHandle> ChildHandle = InStructPropertyHandle->GetChildHandle( ChildIndex ).ToSharedRef();
const FName PropertyName = ChildHandle->GetProperty()->GetFName();
if( PropertyName == Red )
{
ColorProperties[0] = ChildHandle;
}
else if( PropertyName == Green )
{
ColorProperties[1] = ChildHandle;
}
else if( PropertyName == Blue )
{
ColorProperties[2] = ChildHandle;
}
else
{
ColorProperties[3] = ChildHandle;
}
}
OutChildren.Add( ColorProperties[0].ToSharedRef() );
OutChildren.Add( ColorProperties[1].ToSharedRef() );
OutChildren.Add( ColorProperties[2].ToSharedRef() );
// Alpha channel may not be used
if( !bIgnoreAlpha && ColorProperties[3].IsValid() )
{
OutChildren.Add( ColorProperties[3].ToSharedRef() );
}
}
void FColorStructCustomization::CreateColorPicker( bool bUseAlpha, bool bOnlyRefreshOnOk )
{
int32 NumObjects = StructPropertyHandle->GetNumOuterObjects();
SavedPreColorPickerColors.Empty();
TArray<FString> PerObjectValues;
StructPropertyHandle->GetPerObjectValues( PerObjectValues );
for( int32 ObjectIndex = 0; ObjectIndex < NumObjects; ++ObjectIndex )
{
if( bIsLinearColor )
{
FLinearColor Color;
Color.InitFromString( PerObjectValues[ObjectIndex] );
SavedPreColorPickerColors.Add( Color );
}
else
{
FColor Color;
Color.InitFromString( PerObjectValues[ObjectIndex] );
SavedPreColorPickerColors.Add( Color.ReinterpretAsLinear() );
}
}
FLinearColor InitialColor;
GetColorAsLinear(InitialColor);
// This needs to be meta data. Other colors could benefit from this
const bool bRefreshOnlyOnOk = bOnlyRefreshOnOk || StructPropertyHandle->GetProperty()->GetOwnerClass()->IsChildOf(UMaterialExpressionConstant3Vector::StaticClass());
FColorPickerArgs PickerArgs;
PickerArgs.bUseAlpha = !bIgnoreAlpha;
PickerArgs.bOnlyRefreshOnMouseUp = false;
PickerArgs.bOnlyRefreshOnOk = bRefreshOnlyOnOk;
PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) );
PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateSP( this, &FColorStructCustomization::OnSetColorFromColorPicker );
PickerArgs.OnColorPickerCancelled = FOnColorPickerCancelled::CreateSP( this, &FColorStructCustomization::OnColorPickerCancelled );
PickerArgs.OnInteractivePickBegin = FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveBegin );
PickerArgs.OnInteractivePickEnd = FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveEnd );
PickerArgs.InitialColorOverride = InitialColor;
PickerArgs.ParentWidget = ColorPickerParentWidget;
OpenColorPicker(PickerArgs);
}
TSharedRef<SColorPicker> FColorStructCustomization::CreateInlineColorPicker()
{
int32 NumObjects = StructPropertyHandle->GetNumOuterObjects();
SavedPreColorPickerColors.Empty();
TArray<FString> PerObjectValues;
StructPropertyHandle->GetPerObjectValues( PerObjectValues );
for( int32 ObjectIndex = 0; ObjectIndex < NumObjects; ++ObjectIndex )
{
if( bIsLinearColor )
{
FLinearColor Color;
Color.InitFromString( PerObjectValues[ObjectIndex] );
SavedPreColorPickerColors.Add( Color );
}
else
{
FColor Color;
Color.InitFromString( PerObjectValues[ObjectIndex] );
SavedPreColorPickerColors.Add( Color.ReinterpretAsLinear() );
}
}
FLinearColor InitialColor;
GetColorAsLinear(InitialColor);
// This needs to be meta data. Other colors could benefit from this
const bool bRefreshOnlyOnOk = bDontUpdateWhileEditing || StructPropertyHandle->GetProperty()->GetOwnerClass()->IsChildOf(UMaterialExpressionConstant3Vector::StaticClass());
return SNew(SColorPicker)
.Visibility(this, &FColorStructCustomization::GetInlineColorPickerVisibility)
.DisplayInlineVersion(true)
.OnlyRefreshOnMouseUp(false)
.OnlyRefreshOnOk(bRefreshOnlyOnOk)
.DisplayGamma(TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) ))
.OnColorCommitted(FOnLinearColorValueChanged::CreateSP( this, &FColorStructCustomization::OnSetColorFromColorPicker ))
.OnColorPickerCancelled(FOnColorPickerCancelled::CreateSP( this, &FColorStructCustomization::OnColorPickerCancelled ))
.OnInteractivePickBegin(FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveBegin ))
.OnInteractivePickEnd(FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveEnd ))
.TargetColorAttribute(InitialColor);
}
void FColorStructCustomization::OnSetColorFromColorPicker( FLinearColor NewColor )
{
FString ColorString;
if( bIsLinearColor )
{
ColorString = NewColor.ToString();
}
else
{
// Handled by the color picker
const bool bSRGB = false;
FColor NewFColor = NewColor.ToFColor(bSRGB);
ColorString = NewFColor.ToString();
}
StructPropertyHandle->SetValueFromFormattedString( ColorString, bIsInteractive ? EPropertyValueSetFlags::InteractiveChange : 0 );
}
void FColorStructCustomization::OnColorPickerCancelled( FLinearColor OriginalColor )
{
TArray<FString> PerObjectColors;
for( int32 ColorIndex = 0; ColorIndex < SavedPreColorPickerColors.Num(); ++ColorIndex )
{
if( bIsLinearColor )
{
PerObjectColors.Add( SavedPreColorPickerColors[ColorIndex].ToString() );
}
else
{
const bool bSRGB = false;
FColor Color = SavedPreColorPickerColors[ColorIndex].ToFColor( bSRGB );
PerObjectColors.Add( Color.ToString() );
}
}
StructPropertyHandle->SetPerObjectValues( PerObjectColors );
PerObjectColors.Empty();
}
void FColorStructCustomization::OnColorPickerInteractiveBegin()
{
bIsInteractive = true;
GEditor->BeginTransaction( FText::Format( NSLOCTEXT("FColorStructCustomization", "SetColorProperty", "Edit {0}"), FText::FromString( StructPropertyHandle->GetPropertyDisplayName() ) ) );
}
void FColorStructCustomization::OnColorPickerInteractiveEnd()
{
bIsInteractive = false;
if (!bDontUpdateWhileEditing)
{
// pushes the last value from the interactive change without the interactive flag
FString ColorString;
StructPropertyHandle->GetValueAsFormattedString(ColorString);
StructPropertyHandle->SetValueFromFormattedString(ColorString);
}
GEditor->EndTransaction();
}
FLinearColor FColorStructCustomization::OnGetColorForColorBlock() const
{
FLinearColor Color;
GetColorAsLinear(Color);
return Color;
}
FPropertyAccess::Result FColorStructCustomization::GetColorAsLinear(FLinearColor& OutColor) const
{
// Get each color component
for(int32 ChildIndex = 0; ChildIndex < SortedChildHandles.Num(); ++ChildIndex)
{
FPropertyAccess::Result ValueResult = FPropertyAccess::Fail;
if(bIsLinearColor)
{
float ComponentValue = 0;
ValueResult = SortedChildHandles[ChildIndex]->GetValue(ComponentValue);
OutColor.Component(ChildIndex) = ComponentValue;
}
else
{
uint8 ComponentValue = 0;
ValueResult = SortedChildHandles[ChildIndex]->GetValue(ComponentValue);
// Convert the FColor to a linear equivalent
OutColor.Component(ChildIndex) = ComponentValue/255.0f;
}
switch(ValueResult)
{
case FPropertyAccess::MultipleValues:
{
// Default the color to white if we've got multiple values selected
OutColor = FLinearColor::White;
return FPropertyAccess::MultipleValues;
}
case FPropertyAccess::Fail:
return FPropertyAccess::Fail;
default:
break;
}
}
// If we've got this far, we have to have successfully read a color with a single value
return FPropertyAccess::Success;
}
EVisibility FColorStructCustomization::GetMultipleValuesTextVisibility() const
{
FLinearColor Color;
const FPropertyAccess::Result ValueResult = GetColorAsLinear(Color);
return (ValueResult == FPropertyAccess::MultipleValues) ? EVisibility::Visible : EVisibility::Collapsed;
}
FReply FColorStructCustomization::OnMouseButtonDownColorBlock(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if ( MouseEvent.GetEffectingButton() != EKeys::LeftMouseButton )
{
return FReply::Unhandled();
}
CreateColorPicker( /*bUseAlpha*/ true, bDontUpdateWhileEditing);
//bIsInlineColorPickerVisible = !bIsInlineColorPickerVisible;
return FReply::Handled();
}
EVisibility FColorStructCustomization::GetInlineColorPickerVisibility() const
{
return bIsInlineColorPickerVisible ? EVisibility::Visible : EVisibility::Collapsed;
}
FReply FColorStructCustomization::OnOpenFullColorPickerClicked()
{
CreateColorPicker( /*bUseAlpha*/ true, bDontUpdateWhileEditing);
bIsInlineColorPickerVisible = false;
return FReply::Handled();
}
#undef LOCTEXT_NAMESPACE