// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "DetailCustomizationsPrivatePCH.h" #include "IntervalStructCustomization.h" #include "SNumericEntryBox.h" #define LOCTEXT_NAMESPACE "IntervalStructCustomization" /* Helper traits for getting a metadata property based on the template parameter type *****************************************************************************/ namespace IntervalMetadata { template struct FGetHelper { }; template <> struct FGetHelper { static float GetMetaData(const UProperty* Property, const TCHAR* Key) { return Property->GetFLOATMetaData(Key); } }; template <> struct FGetHelper { static int32 GetMetaData(const UProperty* Property, const TCHAR* Key) { return Property->GetINTMetaData(Key); } }; } /* FIntervalStructCustomization static interface *****************************************************************************/ template TSharedRef FIntervalStructCustomization::MakeInstance() { return MakeShareable(new FIntervalStructCustomization); } /* IPropertyTypeCustomization interface *****************************************************************************/ template void FIntervalStructCustomization::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { // Get handles to the properties we're interested in MinValueHandle = StructPropertyHandle->GetChildHandle(TEXT("Min")); MaxValueHandle = StructPropertyHandle->GetChildHandle(TEXT("Max")); check(MinValueHandle.IsValid()); check(MaxValueHandle.IsValid()); // Get min/max metadata values if defined auto Property = StructPropertyHandle->GetProperty(); if (Property != nullptr) { if (Property->HasMetaData(TEXT("UIMin"))) { MinAllowedValue = TOptional(IntervalMetadata::FGetHelper::GetMetaData(Property, TEXT("UIMin"))); } if (Property->HasMetaData(TEXT("UIMax"))) { MaxAllowedValue = TOptional(IntervalMetadata::FGetHelper::GetMetaData(Property, TEXT("UIMax"))); } } // Make weak pointers to be passed as payloads to the widgets TWeakPtr MinValueWeakPtr = MinValueHandle; TWeakPtr MaxValueWeakPtr = MaxValueHandle; // Build the widgets HeaderRow.NameContent() [ StructPropertyHandle->CreatePropertyNameWidget() ] .ValueContent() .MinDesiredWidth(200.0f) //.MaxDesiredWidth(200.0f) [ SNew(SBox) .Padding(FMargin(0.0f, 3.0f, 0.0f, 2.0f)) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .Padding(FMargin(0.0f, 0.0f, 5.0f, 0.0f)) .VAlign(VAlign_Center) [ SNew(SNumericEntryBox) .Value(this, &FIntervalStructCustomization::OnGetValue, MinValueWeakPtr) .MinValue(MinAllowedValue) .MinSliderValue(MinAllowedValue) .MaxValue(this, &FIntervalStructCustomization::OnGetValue, MaxValueWeakPtr) .MaxSliderValue(this, &FIntervalStructCustomization::OnGetValue, MaxValueWeakPtr) .OnValueCommitted(this, &FIntervalStructCustomization::OnValueCommitted, MinValueWeakPtr) .OnValueChanged(this, &FIntervalStructCustomization::OnValueChanged, MinValueWeakPtr) .OnBeginSliderMovement(this, &FIntervalStructCustomization::OnBeginSliderMovement) .OnEndSliderMovement(this, &FIntervalStructCustomization::OnEndSliderMovement) .Font(IDetailLayoutBuilder::GetDetailFont()) .AllowSpin(true) .LabelVAlign(VAlign_Center) .Label() [ SNew(STextBlock) .Font(IDetailLayoutBuilder::GetDetailFont()) .Text(LOCTEXT("MinLabel", "Min")) ] ] +SHorizontalBox::Slot() .Padding(FMargin(0.0f, 0.0f, 5.0f, 0.0f)) .VAlign(VAlign_Center) [ SNew(SNumericEntryBox) .Value(this, &FIntervalStructCustomization::OnGetValue, MaxValueWeakPtr) .MinValue(this, &FIntervalStructCustomization::OnGetValue, MinValueWeakPtr) .MinSliderValue(this, &FIntervalStructCustomization::OnGetValue, MinValueWeakPtr) .MaxValue(MaxAllowedValue) .MaxSliderValue(MaxAllowedValue) .OnValueCommitted(this, &FIntervalStructCustomization::OnValueCommitted, MaxValueWeakPtr) .OnValueChanged(this, &FIntervalStructCustomization::OnValueChanged, MaxValueWeakPtr) .OnBeginSliderMovement(this, &FIntervalStructCustomization::OnBeginSliderMovement) .OnEndSliderMovement(this, &FIntervalStructCustomization::OnEndSliderMovement) .Font(IDetailLayoutBuilder::GetDetailFont()) .AllowSpin(true) .LabelVAlign(VAlign_Center) .Label() [ SNew(STextBlock) .Font(IDetailLayoutBuilder::GetDetailFont()) .Text(LOCTEXT("MaxLabel", "Max")) ] ] ] ]; } template void FIntervalStructCustomization::CustomizeChildren(TSharedRef StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { // Don't display children, as editing them directly can break the constraints } /* FIntervalStructCustomization callbacks *****************************************************************************/ template TOptional FIntervalStructCustomization::OnGetValue(TWeakPtr ValueWeakPtr) const { auto ValueSharedPtr = ValueWeakPtr.Pin(); NumericType Value; if (ValueSharedPtr->GetValue(Value) == FPropertyAccess::Success) { return TOptional(Value); } // Value couldn't be accessed. Return an unset value return TOptional(); } template void FIntervalStructCustomization::OnValueCommitted(NumericType NewValue, ETextCommit::Type CommitType, TWeakPtr HandleWeakPtr) { auto HandleSharedPtr = HandleWeakPtr.Pin(); if (HandleSharedPtr.IsValid() && (!bIsUsingSlider || (bIsUsingSlider && ShouldAllowSpin()))) { ensure(HandleSharedPtr->SetValue(NewValue) == FPropertyAccess::Success); } } template void FIntervalStructCustomization::OnValueChanged(NumericType NewValue, TWeakPtr HandleWeakPtr) { if (bIsUsingSlider && ShouldAllowSpin()) { auto HandleSharedPtr = HandleWeakPtr.Pin(); if (HandleSharedPtr.IsValid()) { ensure(HandleSharedPtr->SetValue(NewValue, EPropertyValueSetFlags::InteractiveChange) == FPropertyAccess::Success); } } } template void FIntervalStructCustomization::OnBeginSliderMovement() { bIsUsingSlider = true; if (ShouldAllowSpin()) { GEditor->BeginTransaction(LOCTEXT("SetIntervalProperty", "Set Interval Property")); } } template void FIntervalStructCustomization::OnEndSliderMovement(NumericType /*NewValue*/) { bIsUsingSlider = false; if (ShouldAllowSpin()) { GEditor->EndTransaction(); } } template bool FIntervalStructCustomization::ShouldAllowSpin() const { return true; } /* Only explicitly instantiate the types which are supported *****************************************************************************/ template class FIntervalStructCustomization; template class FIntervalStructCustomization; #undef LOCTEXT_NAMESPACE