You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
========================== MAJOR FEATURES + CHANGES ========================== Change 2859626 on 2016/02/08 by Max.Preussner Editor: Added SaveAs functionality to content asset editors Change 2859666 on 2016/02/08 by Max.Chen Sequencer: Fix crash in CheckForWorldGCLeaks when loading a new map because spawnables are left behind. #jira UE-25616 Change 2859685 on 2016/02/08 by Max.Chen Sequencer: Add prompt to save sub level sequences if they are dirty #jira UE-26510 Change 2859715 on 2016/02/08 by Thomas.Sarkanen Adding actor spawning recording Actors are queued for record on spawn then added to the list like manually-specifed ones. Changed almost everything about UActorRecording. We now record on a per-component basis, with property tracks encapsulated in each actor recording. Much effort is expended to make sure that the correct components are owned by their respective actors, as we can add and remove components at runtime, but they must be created up-front in the UMovieScene Blueprints. We go as far as to add our own SCS nodes to make sure components are correctly spawned. Fixed infinite loop in FSequencer::AddSpawnable. Fixed visibility track instance to work with scene components as well as actors. Fixed particle track instance to work on UParticleSystemComponent rather than just AEmitters. Added particle recorder. Moved animation recording into an animation property recorder rather than having it as a special case. This still uses the animation recorder under the hood. Moved old-style Matinee animation control into FMovieSceneSkeletalAnimationTrackInstance & made this work on USkeletalMeshComponents directly, rather than via the old interface. Exposed SetMatineeAnimPositionInner and PreviewMatineeSetAnimPositionInner in FAnimMontageInstance so those utility functions can be used externally to Engine. Added a predicate version of UMovieScene::FindPossessable. Exposed UMovieSceneParticleSection::AddKey externally via MOVIESCENETRACKS_API so I can programmatically add keys. Fixed a crash in FScalableFloatDetails::CustomizeHeader when selecting PIE projectiles in Orion. Moved all recorders over to recording Actors or Components & store UObjects instead of AActors. Allowed skeletal animation tracks on components as well as actors. Change 2862675 on 2016/02/10 by Max.Chen Sequencer: Add option to link the sequencer curve editor with the sequencer timeline. Under General Options->Link Curve Editor Time Range. The default is false, so the sequencer and curve editor have separate time ranges. #jira UE-25933 Change 2862699 on 2016/02/11 by Max.Chen Sequencer: Added a playback status of jumping which the AudioTrack and Skeletal Mesh Track (anim notifies) ignores for updates. This is used to updating thumbnail at certain times. #jira UE-26447, UE-26671 Change 2862712 on 2016/02/11 by Max.Chen Sequencer: Fix spawnables firing off their particles. Disable auto activate on spawnable components #jira UE-26390 Change 2862719 on 2016/02/11 by Max.Preussner Editor: Refactored detail customizations for colors, rotators, vectors - broke color and rotator customizations out into their own files - added vector customizations (placeholder) - cleaned up localization namespaces, forward declarations Change 2866454 on 2016/02/14 by Max.Preussner Sequencer: Removed ULevelEditorSequencerSettings; moved default settings into INI Change 2866455 on 2016/02/14 by Thomas.Sarkanen Sequence recorder can now record replays Added extra edtior-only UI to the replay playback controls to record sequences. Curretnly very placeholder: only records the entire sequence and provides no feedback in the UI if it is recording. Fixed bindings to recorded objects not working in various circumstances. Added the ability to manually create a binding. Recompiled actor blueprints post-record if we added components. Fixed a null ptr dereference in FOrionTeamUIInfo::Update. Removed tolerances when reducing tracks - they are now 'very small'. Added actor filter so actors of certain classes can be recorded. Change 2866458 on 2016/02/14 by Max.Chen Sequencer: Fix anim notifies that fire at shot cuts. Anim notifies are fired from the last position to the current position. When jumping cuts, we want the delta to be 0 so that the anim notifies before the shot are not fired off. #jira UE-26390, UE-26671 Change 2866459 on 2016/02/14 by Max.Chen Sequencer: Add option to toggle visibility of combined keys Change 2866466 on 2016/02/14 by Frank.Fella Sequencer - Add a track for controlling streamed level visibilty and remove visibility code from the master level blueprint. Change 2866470 on 2016/02/14 by Max.Chen Sequencer: Add return value to indicate data has changed when a section has been added. This fixes a bug where creating a new section doesn't seem to add a key. #jira UE-26837 Change 2866481 on 2016/02/14 by Max.Preussner Sequencer: Implemented Presets for adding tracks automatically based on actor type (UE-24513) #Jira: UE-24513 Change 2866482 on 2016/02/14 by Max.Chen Sequencer: Allow for any actor that has a camera component to be a camera cut. #jira UE-26777 Change 2866484 on 2016/02/14 by Thomas.Sarkanen Added in/out times to sequence recording Also added the optional ability to record different actor types (heroes, projectiles, minions). Change 2866495 on 2016/02/14 by Max.Chen Sequencer: Need to limit camera control to the section bounds of the camera cut otherwise, control won't be relinquished back to player at the end of the playback. #jira UE-26886 [CL 2874647 by Max Chen in Main branch]
390 lines
14 KiB
C++
390 lines
14 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DetailCustomizationsPrivatePCH.h"
|
|
#include "Materials/MaterialExpressionConstant3Vector.h"
|
|
#include "MathStructCustomizations.h"
|
|
#include "IPropertyUtilities.h"
|
|
#include "SNumericEntryBox.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 FText DisplayNameOverride = FText::GetEmpty();
|
|
const FText DisplayToolTipOverride = FText::GetEmpty();
|
|
|
|
TWeakPtr<IPropertyHandle> StructWeakHandlePtr = StructPropertyHandle;
|
|
|
|
TSharedPtr<SHorizontalBox> HorizontalBox;
|
|
|
|
Row.NameContent()
|
|
[
|
|
StructPropertyHandle->CreatePropertyNameWidget(DisplayNameOverride, DisplayToolTipOverride, 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(StructPropertyHandle, ChildHandle)
|
|
];
|
|
}
|
|
|
|
if (StructPropertyHandle->GetProperty()->HasMetaData("AllowPreserveRatio"))
|
|
{
|
|
if (!GConfig->GetBool(TEXT("SelectionDetails"), *(StructPropertyHandle->GetProperty()->GetName() + TEXT("_PreserveScaleRatio")), bPreserveScaleRatio, GEditorPerProjectIni))
|
|
{
|
|
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"));
|
|
}
|
|
|
|
|
|
ECheckBoxState FMathStructCustomization::IsPreserveScaleRatioChecked() const
|
|
{
|
|
return bPreserveScaleRatio ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
|
|
}
|
|
|
|
|
|
void FMathStructCustomization::OnPreserveScaleRatioToggled(ECheckBoxState NewState, TWeakPtr<IPropertyHandle> PropertyHandle)
|
|
{
|
|
bPreserveScaleRatio = (NewState == ECheckBoxState::Checked) ? true : false;
|
|
|
|
if (PropertyHandle.IsValid() && PropertyHandle.Pin()->GetProperty())
|
|
{
|
|
FString SettingKey = (PropertyHandle.Pin()->GetProperty()->GetName() + TEXT("_PreserveScaleRatio"));
|
|
GConfig->SetBool(TEXT("SelectionDetails"), *SettingKey, bPreserveScaleRatio, GEditorPerProjectIni);
|
|
}
|
|
}
|
|
|
|
|
|
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>
|
|
void ExtractNumericMetadata(TSharedRef<IPropertyHandle>& PropertyHandle, TOptional<NumericType>& MinValue, TOptional<NumericType>& MaxValue, TOptional<NumericType>& SliderMinValue, TOptional<NumericType>& SliderMaxValue, NumericType& SliderExponent, NumericType& Delta)
|
|
{
|
|
UProperty* Property = PropertyHandle->GetProperty();
|
|
|
|
const FString& MetaUIMinString = Property->GetMetaData(TEXT("UIMin"));
|
|
const FString& MetaUIMaxString = Property->GetMetaData(TEXT("UIMax"));
|
|
const FString& SliderExponentString = Property->GetMetaData(TEXT("SliderExponent"));
|
|
const FString& DeltaString = Property->GetMetaData(TEXT("Delta"));
|
|
const FString& ClampMinString = Property->GetMetaData(TEXT("ClampMin"));
|
|
const FString& ClampMaxString = Property->GetMetaData(TEXT("ClampMax"));
|
|
|
|
// If no UIMin/Max was specified then use the clamp string
|
|
const FString& UIMinString = MetaUIMinString.Len() ? MetaUIMinString : ClampMinString;
|
|
const FString& UIMaxString = MetaUIMaxString.Len() ? MetaUIMaxString : ClampMaxString;
|
|
|
|
NumericType ClampMin = TNumericLimits<NumericType>::Lowest();
|
|
NumericType ClampMax = TNumericLimits<NumericType>::Max();
|
|
|
|
if (!ClampMinString.IsEmpty())
|
|
{
|
|
TTypeFromString<NumericType>::FromString(ClampMin, *ClampMinString);
|
|
}
|
|
|
|
if (!ClampMaxString.IsEmpty())
|
|
{
|
|
TTypeFromString<NumericType>::FromString(ClampMax, *ClampMaxString);
|
|
}
|
|
|
|
NumericType UIMin = TNumericLimits<NumericType>::Lowest();
|
|
NumericType UIMax = TNumericLimits<NumericType>::Max();
|
|
TTypeFromString<NumericType>::FromString(UIMin, *UIMinString);
|
|
TTypeFromString<NumericType>::FromString(UIMax, *UIMaxString);
|
|
|
|
SliderExponent = NumericType(1);
|
|
|
|
if (SliderExponentString.Len())
|
|
{
|
|
TTypeFromString<NumericType>::FromString(SliderExponent, *SliderExponentString);
|
|
}
|
|
|
|
Delta = NumericType(0);
|
|
|
|
if (DeltaString.Len())
|
|
{
|
|
TTypeFromString<NumericType>::FromString(Delta, *DeltaString);
|
|
}
|
|
|
|
if (ClampMin >= ClampMax && (ClampMinString.Len() || ClampMaxString.Len()))
|
|
{
|
|
//UE_LOG(LogPropertyNode, Warning, TEXT("Clamp Min (%s) >= Clamp Max (%s) for Ranged Numeric"), *ClampMinString, *ClampMaxString);
|
|
}
|
|
|
|
const NumericType ActualUIMin = FMath::Max(UIMin, ClampMin);
|
|
const NumericType ActualUIMax = FMath::Min(UIMax, ClampMax);
|
|
|
|
MinValue = ClampMinString.Len() ? ClampMin : TOptional<NumericType>();
|
|
MaxValue = ClampMaxString.Len() ? ClampMax : TOptional<NumericType>();
|
|
SliderMinValue = (UIMinString.Len()) ? ActualUIMin : TOptional<NumericType>();
|
|
SliderMaxValue = (UIMaxString.Len()) ? ActualUIMax : TOptional<NumericType>();
|
|
|
|
if (ActualUIMin >= ActualUIMax && (MetaUIMinString.Len() || MetaUIMaxString.Len()))
|
|
{
|
|
//UE_LOG(LogPropertyNode, Warning, TEXT("UI Min (%s) >= UI Max (%s) for Ranged Numeric"), *UIMinString, *UIMaxString);
|
|
}
|
|
}
|
|
|
|
|
|
template<typename NumericType>
|
|
TSharedRef<SWidget> FMathStructCustomization::MakeNumericWidget(
|
|
TSharedRef<IPropertyHandle>& StructurePropertyHandle,
|
|
TSharedRef<IPropertyHandle>& PropertyHandle)
|
|
{
|
|
TOptional<NumericType> MinValue, MaxValue, SliderMinValue, SliderMaxValue;
|
|
NumericType SliderExponent, Delta;
|
|
ExtractNumericMetadata(StructurePropertyHandle, MinValue, MaxValue, SliderMinValue, SliderMaxValue, SliderExponent, Delta);
|
|
|
|
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"))
|
|
.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(MinValue)
|
|
.MaxValue(MaxValue)
|
|
.MinSliderValue(SliderMinValue)
|
|
.MaxSliderValue(SliderMaxValue)
|
|
.SliderExponent(SliderExponent)
|
|
.Delta(Delta)
|
|
.Label()
|
|
[
|
|
SNew(STextBlock)
|
|
.Font(IDetailLayoutBuilder::GetDetailFont())
|
|
.Text(PropertyHandle->GetPropertyDisplayName())
|
|
];
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> FMathStructCustomization::MakeChildWidget(
|
|
TSharedRef<IPropertyHandle>& StructurePropertyHandle,
|
|
TSharedRef<IPropertyHandle>& PropertyHandle)
|
|
{
|
|
const UClass* PropertyClass = PropertyHandle->GetPropertyClass();
|
|
|
|
if (PropertyClass == UFloatProperty::StaticClass())
|
|
{
|
|
return MakeNumericWidget<float>(StructurePropertyHandle, PropertyHandle);
|
|
}
|
|
|
|
if (PropertyClass == UIntProperty::StaticClass())
|
|
{
|
|
return MakeNumericWidget<int32>(StructurePropertyHandle, PropertyHandle);
|
|
}
|
|
|
|
if (PropertyClass == UByteProperty::StaticClass())
|
|
{
|
|
return MakeNumericWidget<uint8>(StructurePropertyHandle, 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(LOCTEXT("SetVectorProperty", "Set Vector Property"));
|
|
}
|
|
|
|
|
|
template<typename NumericType>
|
|
void FMathStructCustomization::OnEndSliderMovement(NumericType NewValue)
|
|
{
|
|
bIsUsingSlider = false;
|
|
|
|
GEditor->EndTransaction();
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|