vault backup: 2024-10-12 17:19:45
After Width: | Height: | Size: 143 KiB |
@@ -0,0 +1,66 @@
|
||||
# AllowPreserveRatio
|
||||
|
||||
- **功能描述:** 在细节面板上为FVector属性添加一个比率锁。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FVector
|
||||
- **常用程度:** ★★★
|
||||
|
||||
在细节面板上为FVector属性添加一个比率锁。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest)
|
||||
FVector MyVector_Default;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest, meta = (AllowPreserveRatio))
|
||||
FVector MyVector_AllowPreserveRatio;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest, meta = (ShowNormalize))
|
||||
FVector MyVector_ShowNormalize;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可见MyVector_AllowPreserveRatio的值在锁上之后可以形成固定的比率。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
其实就是UI定制化的时候检测出AllowPreserveRatio就创建单独的UI。
|
||||
|
||||
```cpp
|
||||
void FMathStructCustomization::MakeHeaderRow(TSharedRef<class IPropertyHandle>& StructPropertyHandle, FDetailWidgetRow& Row)
|
||||
{
|
||||
if (StructPropertyHandle->HasMetaData("AllowPreserveRatio"))
|
||||
{
|
||||
if (!GConfig->GetBool(TEXT("SelectionDetails"), *(StructPropertyHandle->GetProperty()->GetName() + TEXT("_PreserveScaleRatio")), bPreserveScaleRatio, GEditorPerProjectIni))
|
||||
{
|
||||
bPreserveScaleRatio = true;
|
||||
}
|
||||
|
||||
HorizontalBox->AddSlot()
|
||||
.AutoWidth()
|
||||
.MaxWidth(18.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
[
|
||||
// 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(FAppStyle::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())
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 294 KiB |
@@ -0,0 +1,60 @@
|
||||
# ArrayClamp
|
||||
|
||||
- **功能描述:** 限定整数属性的值必须在指定数组的合法下标范围内,[0,ArrayClamp.Size()-1]
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** int32
|
||||
- **限制类型:** int32
|
||||
- **常用程度:** ★★★
|
||||
|
||||
限定整数属性的值必须在指定数组的合法下标范围内,[0,ArrayClamp.Size()-1]
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ArrayClampTest)
|
||||
int32 MyInt_NoArrayClamp = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ArrayClampTest, meta = (ArrayClamp = "MyIntArray"))
|
||||
int32 MyInt_HasArrayClamp = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ArrayClampTest)
|
||||
TArray<int32> MyIntArray;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
可见拥有ArrayClamp的整数值被限制在数组的下标中。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
根据指定的数组名称在本类里寻找到Array属性,然后把本整数属性的值Clamp在该数组的下标范围内。
|
||||
|
||||
```cpp
|
||||
template <typename Type>
|
||||
static Type ClampIntegerValueFromMetaData(Type InValue, FPropertyHandleBase& InPropertyHandle, FPropertyNode& InPropertyNode)
|
||||
{
|
||||
Type RetVal = ClampValueFromMetaData<Type>(InValue, InPropertyHandle);
|
||||
|
||||
//enforce array bounds
|
||||
const FString& ArrayClampString = InPropertyHandle.GetMetaData(TEXT("ArrayClamp"));
|
||||
if (ArrayClampString.Len())
|
||||
{
|
||||
FObjectPropertyNode* ObjectPropertyNode = InPropertyNode.FindObjectItemParent();
|
||||
if (ObjectPropertyNode && ObjectPropertyNode->GetNumObjects() == 1)
|
||||
{
|
||||
Type LastValidIndex = static_cast<Type>(GetArrayPropertyLastValidIndex(ObjectPropertyNode, ArrayClampString));
|
||||
RetVal = FMath::Clamp<Type>(RetVal, 0, LastValidIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogPropertyNode, Warning, TEXT("Array Clamping isn't supported in multi-select (Param Name: %s)"), *InPropertyHandle.GetProperty()->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
```
|
@@ -0,0 +1,9 @@
|
||||
# ClampMax
|
||||
|
||||
- **功能描述:** 指定数字输入框实际接受的最大值
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [UIMin](UIMin/UIMin.md)
|
||||
- **常用程度:** ★★★★★
|
@@ -0,0 +1,9 @@
|
||||
# ClampMin
|
||||
|
||||
- **功能描述:** 指定数字输入框实际接受的最小值
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [UIMin](UIMin/UIMin.md)
|
||||
- **常用程度:** ★★★★★
|
@@ -0,0 +1,103 @@
|
||||
# ColorGradingMode
|
||||
|
||||
- **功能描述:** 使得一个FVector4属性成为颜色显示
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** string="abc"
|
||||
- **限制类型:** FVector4
|
||||
- **常用程度:** ★★
|
||||
|
||||
使得一个FVector4属性成为颜色显示。因为FVector4和RGBA正好对应。
|
||||
|
||||
必须配合UIMin,UIMax才能使用,否则会崩溃,因为FColorGradingVectorCustomization里直接对UIMinValue直接取值。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = ())
|
||||
FVector4 MyVector4_NotColor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = (UIMin = "0", UIMax = "1",ColorGradingMode = "saturation"))
|
||||
FVector4 MyVector4_Saturation;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = (UIMin = "0", UIMax = "1",ColorGradingMode = "contrast"))
|
||||
FVector4 MyVector4_Contrast;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = (UIMin = "0", UIMax = "1",ColorGradingMode = "gamma"))
|
||||
FVector4 MyVector4_Gamma;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = (UIMin = "0", UIMax = "1",ColorGradingMode = "gain"))
|
||||
FVector4 MyVector4_Gain;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = ColorGradingModeTest, meta = (UIMin = "0", UIMax = "1",ColorGradingMode = "offset"))
|
||||
FVector4 MyVector4_Offset;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
可以发现没有ColorGradingMode 的依然是普通的FVector4,否则就会用颜色转盘来显示编辑。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
如果是FVector4属性,再判断如果有ColorGradingMode,则创建FColorGradingVectorCustomization来把FVector定制化会颜色显示。再根据字符串判断EColorGradingModes,最后创建相应的具体UI控件。
|
||||
|
||||
```cpp
|
||||
void FVector4StructCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> StructPropertyHandle, IDetailChildrenBuilder& StructBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
||||
{
|
||||
FProperty* Property = StructPropertyHandle->GetProperty();
|
||||
if (Property)
|
||||
{
|
||||
const FString& ColorGradingModeString = Property->GetMetaData(TEXT("ColorGradingMode"));
|
||||
if (!ColorGradingModeString.IsEmpty())
|
||||
{
|
||||
//Create our color grading customization shared pointer
|
||||
TSharedPtr<FColorGradingVectorCustomization> ColorGradingCustomization = GetOrCreateColorGradingVectorCustomization(StructPropertyHandle);
|
||||
|
||||
//Customize the childrens
|
||||
ColorGradingVectorCustomization->CustomizeChildren(StructBuilder, StructCustomizationUtils);
|
||||
|
||||
// We handle the customize Children so just return here
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Use the base class customize children
|
||||
FMathStructCustomization::CustomizeChildren(StructPropertyHandle, StructBuilder, StructCustomizationUtils);
|
||||
}
|
||||
|
||||
EColorGradingModes FColorGradingVectorCustomizationBase::GetColorGradingMode() const
|
||||
{
|
||||
EColorGradingModes ColorGradingMode = EColorGradingModes::Invalid;
|
||||
|
||||
if (ColorGradingPropertyHandle.IsValid())
|
||||
{
|
||||
//Query all meta data we need
|
||||
FProperty* Property = ColorGradingPropertyHandle.Pin()->GetProperty();
|
||||
const FString& ColorGradingModeString = Property->GetMetaData(TEXT("ColorGradingMode"));
|
||||
|
||||
if (ColorGradingModeString.Len() > 0)
|
||||
{
|
||||
if (ColorGradingModeString.Compare(TEXT("saturation")) == 0)
|
||||
{
|
||||
ColorGradingMode = EColorGradingModes::Saturation;
|
||||
}
|
||||
else if (ColorGradingModeString.Compare(TEXT("contrast")) == 0)
|
||||
{
|
||||
ColorGradingMode = EColorGradingModes::Contrast;
|
||||
}
|
||||
else if (ColorGradingModeString.Compare(TEXT("gamma")) == 0)
|
||||
{
|
||||
ColorGradingMode = EColorGradingModes::Gamma;
|
||||
}
|
||||
else if (ColorGradingModeString.Compare(TEXT("gain")) == 0)
|
||||
{
|
||||
ColorGradingMode = EColorGradingModes::Gain;
|
||||
}
|
||||
else if (ColorGradingModeString.Compare(TEXT("offset")) == 0)
|
||||
{
|
||||
ColorGradingMode = EColorGradingModes::Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ColorGradingMode;
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 127 KiB |
@@ -0,0 +1,71 @@
|
||||
# CtrlMultiplier
|
||||
|
||||
- **功能描述:** 指定数字输入框在Ctrl按下时鼠标轮滚动和鼠标拖动改变值的倍率。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** 数据结构:FVector,FRotator,FColor
|
||||
- **关联项:** [ShiftMultiplier](../ShiftMultiplier.md)
|
||||
- **常用程度:** ★★
|
||||
|
||||
指定数字输入框在Ctrl按下时鼠标轮滚动和鼠标拖动改变值的倍率。
|
||||
|
||||
- CtrlMultiplier的默认值是0.1f,一般作为一种精调模式。
|
||||
- 直接设置到float属性上并无效果。默认情况下,属性上的CtrlMultiplier并不会设置到SNumericEntryBox和SSpinBox上,因为这二者并不会直接从property上提取meta来设置到其本身的Multiplier值上。
|
||||
- 在源码里发现FMathStructCustomization里会提取CtrlMultiplier和ShiftMultiplier的值,因此我们可以在一些数学结构上设置,如FVector,FRotator,FColor
|
||||
- 如果自己定义Customization和创建SSpinBox,则可以自己提取Multiplier的值自己设置到控件里去。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultiplierTest, meta = (CtrlMultiplier = "5"))
|
||||
float MyFloat_HasCtrlMultiplier = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultiplierTest, meta = (ShiftMultiplier = "100"))
|
||||
float MyFloat_HasShiftMultiplier = 100;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultiplierTest)
|
||||
FVector MyVector_NoMultiplier;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultiplierTest, meta = (CtrlMultiplier = "5"))
|
||||
FVector MyVector_HasCtrlMultiplier;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultiplierTest, meta = (ShiftMultiplier = "100"))
|
||||
FVector MyVector_HasShiftMultiplier;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
- 发现普通float属性测试并无效果,按下Ctrl和Shift依然是默认的改变值0.1和10.f
|
||||
- 普通的默认FVector,按下Ctrl和Shift也是默认的改变值0.1和10.f
|
||||
- MyVector_HasCtrlMultiplier,发现按下Ctrl,一下子改变幅度是5
|
||||
- MyVector_HasShiftMultiplier,发现按下Shift,一下子改变幅度是100
|
||||
- 当然用鼠标拖动也是一样的效果,只是那样改变太过剧烈,演示效果不明显
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
SNumericEntryBox的构造函数里:
|
||||
, _ShiftMultiplier(10.f)
|
||||
, _CtrlMultiplier(0.1f)
|
||||
|
||||
void FMathStructCustomization::MakeHeaderRow(TSharedRef<class IPropertyHandle>& StructPropertyHandle, FDetailWidgetRow& Row)
|
||||
{
|
||||
for (int32 ChildIndex = 0; ChildIndex < SortedChildHandles.Num(); ++ChildIndex)
|
||||
{
|
||||
TSharedRef<IPropertyHandle> ChildHandle = SortedChildHandles[ChildIndex];
|
||||
|
||||
// Propagate metadata to child properties so that it's reflected in the nested, individual spin boxes
|
||||
ChildHandle->SetInstanceMetaData(TEXT("UIMin"), StructPropertyHandle->GetMetaData(TEXT("UIMin")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("UIMax"), StructPropertyHandle->GetMetaData(TEXT("UIMax")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("SliderExponent"), StructPropertyHandle->GetMetaData(TEXT("SliderExponent")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("Delta"), StructPropertyHandle->GetMetaData(TEXT("Delta")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("LinearDeltaSensitivity"), StructPropertyHandle->GetMetaData(TEXT("LinearDeltaSensitivity")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("ShiftMultiplier"), StructPropertyHandle->GetMetaData(TEXT("ShiftMultiplier")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("CtrlMultiplier"), StructPropertyHandle->GetMetaData(TEXT("CtrlMultiplier")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("SupportDynamicSliderMaxValue"), StructPropertyHandle->GetMetaData(TEXT("SupportDynamicSliderMaxValue")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("SupportDynamicSliderMinValue"), StructPropertyHandle->GetMetaData(TEXT("SupportDynamicSliderMinValue")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("ClampMin"), StructPropertyHandle->GetMetaData(TEXT("ClampMin")));
|
||||
ChildHandle->SetInstanceMetaData(TEXT("ClampMax"), StructPropertyHandle->GetMetaData(TEXT("ClampMax")));
|
||||
}
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 201 KiB |
After Width: | Height: | Size: 356 KiB |
@@ -0,0 +1,111 @@
|
||||
# Delta
|
||||
|
||||
- **功能描述:** 设定数字输入框值改变的幅度为Delta的倍数
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [LinearDeltaSensitivity](../LinearDeltaSensitivity.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
设定数字输入框值改变的幅度为Delta的倍数。
|
||||
|
||||
## 注意的事项是:
|
||||
|
||||
1. 在全局使得变化值成为Delta的倍数
|
||||
2. Delta默认值是0,这个时候代表没有设置,数字会指数改变。
|
||||
3. 注意和WheelStep的区别是,Delta在鼠标左右拖动和按下键盘方向键的时候生效,WheelStep是只在鼠标滚轮变化的时候生效。二者虽然都是用来控制变化幅度,但作用范围不同。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest)
|
||||
float MyFloat_DefaultDelta = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (Delta = 10))
|
||||
float MyFloat_Delta10 = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (UIMin = "0", UIMax = "1000", Delta = 10))
|
||||
float MyFloat_Delta10_UIMinMax = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (Delta = 10, LinearDeltaSensitivity = 50))
|
||||
float MyFloat_Delta10_LinearDeltaSensitivity50 = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (UIMin = "0", UIMax = "1000", Delta = 10, LinearDeltaSensitivity = 50))
|
||||
float MyFloat_Delta10_LinearDeltaSensitivity50_UIMinMax = 100;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
- MyFloat_DefaultDelta ,默认情况下鼠标往右拖动变化很剧烈,变化呈指数上升。
|
||||
- MyFloat_Delta10,鼠标往右拖动变化也很剧烈(最终到达的值也很巨大),但是变化始终以Delta为步幅。
|
||||
- MyFloat_Delta10_UIMinMax ,限定了UIMinMax,导致最大值受限,但是变化其实是按照比例值线性(SliderExponent默认是1没有改变)。
|
||||
- MyFloat_Delta10_LinearDeltaSensitivity50 ,在没有UIMinMax的情况下,且同时设置了LinearDeltaSensitivity,会导致鼠标往右拖动的整个过程中变化值始终是线性。LinearDeltaSensitivity越大越不敏感。因此一次一次缓慢的改变10
|
||||
- MyFloat_Delta10_LinearDeltaSensitivity50_UIMinMax ,如果上面一个再加上UIMinMax,则发现又失去了LinearDeltaSensitivity的效果。因为LinearDeltaSensitivity不能在有滚动条的情况下生效。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
- 在方向键上下左右按键的时候每次变化正负Delta,但是OnKeyDown没有直接绑定,所以默认情况下按键只会触发焦点的转移。
|
||||
- 基础step是0.1或1,如果没受到CtrlMultiplier和ShiftMultiplier的影响。
|
||||
- 默认情况下,鼠标左右移动改变的差量中的指数部分是FMath::Pow((double)CurrentValue, (double)SliderExponent.Get()),SliderExponent默认是1,也就是越往左右两端改变的幅度越大。
|
||||
- 在同时设置LinearDeltaSensitivity和Delta的情况下,鼠标左右移动改变的差量中的指数部分是FMath::Pow((double)Delta.Get(), (double)SliderExponent.Get()),即改变的差量在左右整个数轴上是线性一致的。
|
||||
- 在最后提交值的时候,改变的差量值会被规范到Delta的倍数上来。
|
||||
|
||||
```cpp
|
||||
, _Delta(0)
|
||||
virtual FReply SSpinBox<NumericType>::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
|
||||
{
|
||||
if (bUnlimitedSpinRange)
|
||||
{
|
||||
// If this control has a specified delta and sensitivity then we use that instead of the current value for determining how much to change.
|
||||
const double Sign = (MouseEvent.GetCursorDelta().X > 0) ? 1.0 : -1.0;
|
||||
|
||||
if (LinearDeltaSensitivity.IsSet() && LinearDeltaSensitivity.Get() != 0 && Delta.IsSet() && Delta.Get() > 0)
|
||||
{
|
||||
const double MouseDelta = FMath::Abs(MouseEvent.GetCursorDelta().X / (float)LinearDeltaSensitivity.Get());
|
||||
NewValue = InternalValue + (Sign * MouseDelta * FMath::Pow((double)Delta.Get(), (double)SliderExponent.Get())) * Step;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double MouseDelta = FMath::Abs(MouseEvent.GetCursorDelta().X / SliderWidthInSlateUnits);
|
||||
const double CurrentValue = FMath::Clamp<double>(FMath::Abs(InternalValue), 1.0, (double)std::numeric_limits<NumericType>::max());
|
||||
NewValue = InternalValue + (Sign * MouseDelta * FMath::Pow((double)CurrentValue, (double)SliderExponent.Get())) * Step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual FReply SSpinBox<NumericType>::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override
|
||||
{
|
||||
else if (Key == EKeys::Up || Key == EKeys::Right)
|
||||
{
|
||||
const NumericType LocalValueAttribute = ValueAttribute.Get();
|
||||
const NumericType LocalDelta = Delta.Get();
|
||||
InternalValue = (double)LocalValueAttribute;
|
||||
CommitValue(LocalValueAttribute + LocalDelta, InternalValue + (double)LocalDelta, CommittedViaArrowKey, ETextCommit::OnEnter);
|
||||
ExitTextMode();
|
||||
return FReply::Handled();
|
||||
}
|
||||
else if (Key == EKeys::Down || Key == EKeys::Left)
|
||||
{
|
||||
const NumericType LocalValueAttribute = ValueAttribute.Get();
|
||||
const NumericType LocalDelta = Delta.Get();
|
||||
InternalValue = (double)LocalValueAttribute;
|
||||
CommitValue(LocalValueAttribute - LocalDelta, InternalValue + (double)LocalDelta, CommittedViaArrowKey, ETextCommit::OnEnter);
|
||||
ExitTextMode();
|
||||
return FReply::Handled();
|
||||
}
|
||||
}
|
||||
|
||||
void SSpinBox<NumericType>::CommitValue(NumericType NewValue, double NewSpinValue, ECommitMethod CommitMethod, ETextCommit::Type OriginalCommitInfo)
|
||||
{
|
||||
// If needed, round this value to the delta. Internally the value is not held to the Delta but externally it appears to be.
|
||||
if (CommitMethod == CommittedViaSpin || CommitMethod == CommittedViaArrowKey || bAlwaysUsesDeltaSnap)
|
||||
{
|
||||
NumericType CurrentDelta = Delta.Get();
|
||||
if (CurrentDelta != NumericType())
|
||||
{
|
||||
NewValue = FMath::GridSnap<NumericType>(NewValue, CurrentDelta); // snap numeric point value to nearest Delta
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
@@ -0,0 +1,9 @@
|
||||
# ForceUnits
|
||||
|
||||
- **功能描述:** 固定设定属性值的单位保持不变,不根据数值动态调整显示单位。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** string="abc"
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [Units](Units/Units.md)
|
||||
- **常用程度:** ★★★
|
@@ -0,0 +1,45 @@
|
||||
# HideAlphaChannel
|
||||
|
||||
- **功能描述:** 使FColor或FLinearColor属性在编辑的时候隐藏Alpha通道。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FColor , FLinearColor
|
||||
- **常用程度:** ★★★
|
||||
|
||||
使FColor或FLinearColor属性在编辑的时候隐藏Alpha通道。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, Category = AlphaTest)
|
||||
FColor MyColor;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = AlphaTest, meta = (HideAlphaChannel))
|
||||
FColor MyColor_HideAlphaChannel;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = AlphaTest)
|
||||
FLinearColor MyLinearColor;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = AlphaTest, meta = (HideAlphaChannel))
|
||||
FLinearColor MyLinearColor_HideAlphaChannel;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可见带有HideAlphaChannel的属性就没有了Alpha通道。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
void FColorStructCustomization::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
||||
{
|
||||
bIgnoreAlpha = TypeSupportsAlpha() == false || StructPropertyHandle->GetProperty()->HasMetaData(TEXT("HideAlphaChannel"));
|
||||
}
|
||||
|
||||
.AlphaDisplayMode(bIgnoreAlpha ? EColorBlockAlphaDisplayMode::Ignore : EColorBlockAlphaDisplayMode::Separate)
|
||||
|
||||
```
|
After Width: | Height: | Size: 177 KiB |
@@ -0,0 +1,44 @@
|
||||
# InlineColorPicker
|
||||
|
||||
- **功能描述:** 使FColor或FLinearColor属性在编辑的时候直接内联一个颜色选择器。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FColor , FLinearColor
|
||||
- **常用程度:** ★★
|
||||
|
||||
使FColor或FLinearColor属性在编辑的时候直接内联一个颜色选择器。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, Category = ColorPicker, meta = (InlineColorPicker))
|
||||
FColor MyColor_InlineColorPicker;
|
||||
UPROPERTY(EditAnywhere, Category = ColorPicker, meta = (InlineColorPicker))
|
||||
FLinearColor MyLinearColor_InlineColorPicker;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
根据不同的标记创建不同的的ColorWidget 。
|
||||
|
||||
```cpp
|
||||
|
||||
void FColorStructCustomization::MakeHeaderRow(TSharedRef<class IPropertyHandle>& InStructPropertyHandle, FDetailWidgetRow& Row)
|
||||
{
|
||||
if (InStructPropertyHandle->HasMetaData("InlineColorPicker"))
|
||||
{
|
||||
ColorWidget = CreateInlineColorPicker(StructWeakHandlePtr);
|
||||
ContentWidth = 384.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ColorWidget = CreateColorWidget(StructWeakHandlePtr);
|
||||
}
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 438 KiB |
@@ -0,0 +1,61 @@
|
||||
# LinearDeltaSensitivity
|
||||
|
||||
- **功能描述:** 在设定Delta后,进一步设定数字输入框变成线性改变以及改变的敏感度(值越大越不敏感)
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [Delta](Delta/Delta.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
生效的条件:
|
||||
|
||||
1. 先设置Delta>0
|
||||
2. 不设置UIMin, UIMax
|
||||
3. 设定LinearDeltaSensitivity >0
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (UIMin = "0", UIMax = "1000", Delta = 10))
|
||||
float MyFloat_Delta10_UIMinMax = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (Delta = 10, LinearDeltaSensitivity = 50))
|
||||
float MyFloat_Delta10_LinearDeltaSensitivity50 = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DeltaTest, meta = (UIMin = "0", UIMax = "1000", Delta = 10, LinearDeltaSensitivity = 50))
|
||||
float MyFloat_Delta10_LinearDeltaSensitivity50_UIMinMax = 100;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
效果解析请参见:Delta的解析
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
可见只有没有UIMinMax且已经设置Delta后才能走进线性改变的代码分支。
|
||||
|
||||
```cpp
|
||||
, _Delta(0)
|
||||
virtual FReply SSpinBox<NumericType>::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
|
||||
{
|
||||
if (bUnlimitedSpinRange)
|
||||
{
|
||||
// If this control has a specified delta and sensitivity then we use that instead of the current value for determining how much to change.
|
||||
const double Sign = (MouseEvent.GetCursorDelta().X > 0) ? 1.0 : -1.0;
|
||||
|
||||
if (LinearDeltaSensitivity.IsSet() && LinearDeltaSensitivity.Get() != 0 && Delta.IsSet() && Delta.Get() > 0)
|
||||
{
|
||||
const double MouseDelta = FMath::Abs(MouseEvent.GetCursorDelta().X / (float)LinearDeltaSensitivity.Get());
|
||||
NewValue = InternalValue + (Sign * MouseDelta * FMath::Pow((double)Delta.Get(), (double)SliderExponent.Get())) * Step;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double MouseDelta = FMath::Abs(MouseEvent.GetCursorDelta().X / SliderWidthInSlateUnits);
|
||||
const double CurrentValue = FMath::Clamp<double>(FMath::Abs(InternalValue), 1.0, (double)std::numeric_limits<NumericType>::max());
|
||||
NewValue = InternalValue + (Sign * MouseDelta * FMath::Pow((double)CurrentValue, (double)SliderExponent.Get())) * Step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
After Width: | Height: | Size: 67 KiB |
@@ -0,0 +1,52 @@
|
||||
# Multiple
|
||||
|
||||
- **功能描述:** 指定数字的值必须是Mutliple提供的值的整数倍。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** int32
|
||||
- **限制类型:** int32
|
||||
- **常用程度:** ★★★
|
||||
|
||||
指定数字的值必须是Mutliple提供的值的整数倍。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultipleTest)
|
||||
int32 MyInt_NoMultiple = 100;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MultipleTest, meta = (Multiple = 5))
|
||||
int32 MyInt_HasMultiple = 100;
|
||||
```
|
||||
|
||||
## 蓝图效果:
|
||||
|
||||
可以看到,拥有Multiple 的只能按照5的倍数来增长。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
template <typename Type>
|
||||
static Type ClampIntegerValueFromMetaData(Type InValue, FPropertyHandleBase& InPropertyHandle, FPropertyNode& InPropertyNode)
|
||||
{
|
||||
Type RetVal = ClampValueFromMetaData<Type>(InValue, InPropertyHandle);
|
||||
|
||||
//if there is "Multiple" meta data, the selected number is a multiple
|
||||
const FString& MultipleString = InPropertyHandle.GetMetaData(TEXT("Multiple"));
|
||||
if (MultipleString.Len())
|
||||
{
|
||||
check(MultipleString.IsNumeric());
|
||||
Type MultipleValue;
|
||||
TTypeFromString<Type>::FromString(MultipleValue, *MultipleString);
|
||||
if (MultipleValue != 0)
|
||||
{
|
||||
RetVal -= Type(RetVal) % MultipleValue;
|
||||
}
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
}
|
||||
```
|
@@ -0,0 +1,80 @@
|
||||
# NoSpinbox
|
||||
|
||||
- **功能描述:** 使数值属性禁止默认的拖放和滚轮的UI编辑功能,数值属性包括int系列以及float系列。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** Numeric Type, int / float
|
||||
- **常用程度:** ★★
|
||||
|
||||
使数值属性禁止默认的拖放和滚轮的UI编辑功能,数值属性包括int系列以及float系列。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=SpinBoxTest)
|
||||
int32 MyInt = 123;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=SpinBoxTest, meta = (NoSpinbox = true))
|
||||
int32 MyInt_NoSpinbox = 123;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=SpinBoxTest)
|
||||
float MyFloat = 123;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,Category=SpinBoxTest, meta = (NoSpinbox = true))
|
||||
float MyFloat_NoSpinbox = 123;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
发现带有NoSpinbox 的属性不能用鼠标左右拖动改变数值,也不能用鼠标滚轮改变数值。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
可以看到针对数值的UI,bAllowSpin的功能直接决定了Widget的AllowWheel和AllowSpin功能。
|
||||
|
||||
```cpp
|
||||
virtual TSharedRef<SWidget> GetDefaultValueWidget() override
|
||||
{
|
||||
const typename TNumericPropertyParams<NumericType>::FMetaDataGetter MetaDataGetter = TNumericPropertyParams<NumericType>::FMetaDataGetter::CreateLambda([&](const FName& Key)
|
||||
{
|
||||
return (PinProperty) ? PinProperty->GetMetaData(Key) : FString();
|
||||
});
|
||||
|
||||
TNumericPropertyParams<NumericType> NumericPropertyParams(PinProperty, PinProperty ? MetaDataGetter : nullptr);
|
||||
|
||||
const bool bAllowSpin = !(PinProperty && PinProperty->GetBoolMetaData("NoSpinbox"));
|
||||
|
||||
// Save last committed value to compare when value changes
|
||||
LastSliderCommittedValue = GetNumericValue().GetValue();
|
||||
|
||||
return SNew(SBox)
|
||||
.MinDesiredWidth(MinDesiredBoxWidth)
|
||||
.MaxDesiredWidth(400)
|
||||
[
|
||||
SNew(SNumericEntryBox<NumericType>)
|
||||
.EditableTextBoxStyle(FAppStyle::Get(), "Graph.EditableTextBox")
|
||||
.BorderForegroundColor(FSlateColor::UseForeground())
|
||||
.Visibility(this, &SGraphPinNumSlider::GetDefaultValueVisibility)
|
||||
.IsEnabled(this, &SGraphPinNumSlider::GetDefaultValueIsEditable)
|
||||
.Value(this, &SGraphPinNumSlider::GetNumericValue)
|
||||
.MinValue(NumericPropertyParams.MinValue)
|
||||
.MaxValue(NumericPropertyParams.MaxValue)
|
||||
.MinSliderValue(NumericPropertyParams.MinSliderValue)
|
||||
.MaxSliderValue(NumericPropertyParams.MaxSliderValue)
|
||||
.SliderExponent(NumericPropertyParams.SliderExponent)
|
||||
.Delta(NumericPropertyParams.Delta)
|
||||
.LinearDeltaSensitivity(NumericPropertyParams.GetLinearDeltaSensitivityAttribute())
|
||||
.AllowWheel(bAllowSpin)
|
||||
.WheelStep(NumericPropertyParams.WheelStep)
|
||||
.AllowSpin(bAllowSpin)
|
||||
.OnValueCommitted(this, &SGraphPinNumSlider::OnValueCommitted)
|
||||
.OnValueChanged(this, &SGraphPinNumSlider::OnValueChanged)
|
||||
.OnBeginSliderMovement(this, &SGraphPinNumSlider::OnBeginSliderMovement)
|
||||
.OnEndSliderMovement(this, &SGraphPinNumSlider::OnEndSliderMovement)
|
||||
];
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 192 KiB |
@@ -0,0 +1,13 @@
|
||||
# ShiftMultiplier
|
||||
|
||||
- **功能描述:** 指定数字输入框在Shift按下时鼠标轮滚动和鼠标拖动改变值的倍率。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** 数据结构:FVector,FRotator,FColor
|
||||
- **关联项:** [CtrlMultiplier](CtrlMultiplier/CtrlMultiplier.md)
|
||||
- **常用程度:** ★★
|
||||
|
||||
默认值是10.f
|
||||
|
||||
Shift的模式可以认为是一种快调模式,可以快速的改变值。
|
After Width: | Height: | Size: 143 KiB |
@@ -0,0 +1,55 @@
|
||||
# ShowNormalize
|
||||
|
||||
- **功能描述:** 使得FVector变量在细节面板出现一个正规化的按钮。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FVector
|
||||
- **常用程度:** ★★★
|
||||
|
||||
使得FVector变量在细节面板出现一个正规化的按钮。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest)
|
||||
FVector MyVector_Default;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest, meta = (AllowPreserveRatio))
|
||||
FVector MyVector_AllowPreserveRatio;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = VectorTest, meta = (ShowNormalize))
|
||||
FVector MyVector_ShowNormalize;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
MyVector_ShowNormalize右侧的按钮可以把值正规化。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
其实就是UI定制化的时候检测出ShowNormalize就创建单独的UI。
|
||||
|
||||
```cpp
|
||||
if (StructPropertyHandle->HasMetaData("ShowNormalize") && MathStructCustomization::IsFloatVector(StructPropertyHandle))
|
||||
{
|
||||
HorizontalBox->AddSlot()
|
||||
.AutoWidth()
|
||||
.MaxWidth(18.0f)
|
||||
.VAlign(VAlign_Center)
|
||||
[
|
||||
// Add a button to scale the vector uniformly to achieve a unit vector
|
||||
SNew(SButton)
|
||||
.OnClicked(this, &FMathStructCustomization::OnNormalizeClicked, StructWeakHandlePtr)
|
||||
.ButtonStyle(FAppStyle::Get(), "NoBorder")
|
||||
.ToolTipText(LOCTEXT("NormalizeToolTip", "When clicked, if the vector is large enough, it scales the vector uniformly to achieve a unit vector (vector with a length of 1)"))
|
||||
[
|
||||
SNew(SImage)
|
||||
.ColorAndOpacity(FSlateColor::UseForeground())
|
||||
.Image(FAppStyle::GetBrush(TEXT("Icons.Normalize")))
|
||||
]
|
||||
];
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 204 KiB |
@@ -0,0 +1,51 @@
|
||||
# SliderExponent
|
||||
|
||||
- **功能描述:** 指定数字输入框上滚动条拖动的变化指数分布
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
指定数字输入框上滚动条拖动的变化指数分布。默认值是1。
|
||||
|
||||
该值必须配合Min,Max使用
|
||||
|
||||
所谓指数分布指的是在UIMin和Max的范围内,当滚动的文本值变化的时候,滚动条的百分比值如何变化。默认情况下,中间点的值就是在50%。但我们也可以指定一个指数,形成一条指数分布曲线,在数轴左侧一开始的时候比较平缓变动比较缓慢拥有更高的调整精度,在数轴的右侧结束的部分曲线变得陡峭变动剧烈就失去了精度。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SliderTest, meta = (UIMin = "0", UIMax = "1000"))
|
||||
float MyFloat_DefaultSliderExponent = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SliderTest, meta = (UIMin = "0", UIMax = "1000", SliderExponent = 5))
|
||||
float MyFloat_HasSliderExponent = 100;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
可见SliderExponent=5的效果导致100的文本值落在UI 1000的范围内一开始就处于快0.3的位置,且变动的范围在500前比较精细,500后比较迅速。跟前者形成对比。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
默认的值是1,如果不是,则采用SpinBoxComputeExponentSliderFraction来计算新的百分比,读者可自行观察SpinBoxComputeExponentSliderFraction函数来了解指数分布的情况。
|
||||
|
||||
```cpp
|
||||
const float CachedSliderExponent = SliderExponent.Get();
|
||||
if (!FMath::IsNearlyEqual(CachedSliderExponent, 1.f))
|
||||
{
|
||||
if (SliderExponentNeutralValue.IsSet() && SliderExponentNeutralValue.Get() > GetMinSliderValue() && SliderExponentNeutralValue.Get() < GetMaxSliderValue())
|
||||
{
|
||||
//Compute a log curve on both side of the neutral value
|
||||
float StartFractionFilled = Fraction((double)SliderExponentNeutralValue.Get(), (double)GetMinSliderValue(), (double)GetMaxSliderValue());
|
||||
FractionFilled = SpinBoxComputeExponentSliderFraction(FractionFilled, StartFractionFilled, CachedSliderExponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
FractionFilled = 1.0f - FMath::Pow(1.0f - FractionFilled, CachedSliderExponent);
|
||||
}
|
||||
}
|
||||
```
|
@@ -0,0 +1,9 @@
|
||||
# SupportDynamicSliderMaxValue
|
||||
|
||||
- **功能描述:** 支持数字输入框上滚动条的最大范围值在Alt按下时被动态改变
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FVector4
|
||||
- **关联项:** [SupportDynamicSliderMinValue](SupportDynamicSliderMinValue/SupportDynamicSliderMinValue.md)
|
||||
- **常用程度:** ★
|
After Width: | Height: | Size: 255 KiB |
@@ -0,0 +1,86 @@
|
||||
# SupportDynamicSliderMinValue
|
||||
|
||||
- **功能描述:** 支持数字输入框上滚动条的最小范围值在Alt按下时被动态改变
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FVector4
|
||||
- **关联项:** [SupportDynamicSliderMaxValue](../SupportDynamicSliderMaxValue.md)
|
||||
- **常用程度:** ★
|
||||
|
||||
支持数字输入框上滚动条的最小范围值在Alt按下时被动态改变。
|
||||
|
||||
- 必须配合UIMin,UIMax使用,因为这样才有滚动条UI
|
||||
- 一般情况下滚动条范围是初始设置好的,但该设置支持动态改变。方法是按下Alt拖动鼠标。
|
||||
- 普通的float属性等是不支持该meta的,因为普通自动生成的的SPropertyEditorNumeric,没有从property meta中提取SupportDynamicSliderMinValue,因此即使设置了也不会生效。
|
||||
- 目前源码中只有继承了FMathStructCustomization的FColorGradingVectorCustomizationBase(对应FVector4)才提取SupportDynamicSliderMinValue,然后自己创建SNumericEntryBox,从而正确的设置SupportDynamicSliderMinValue的值。
|
||||
- 因此如果你也想使得自己的结构里的数字属性支持该功能,也需要手动创建Customization,然后在里面手动创建SNumericEntryBox,从而自己设置SupportDynamicSliderMinValue的值。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicSliderTest, meta = (UIMin = "0", UIMax = "1"))
|
||||
FVector4 MyVector4_NoDynamicSlider;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicSliderTest, meta = (UIMin = "0", UIMax = "1", SupportDynamicSliderMinValue = "true", SupportDynamicSliderMaxValue = "true"))
|
||||
FVector4 MyVector4_SupportDynamicSlider;
|
||||
```
|
||||
|
||||
## 测试结果:
|
||||
|
||||
可以看见MyVector4_NoDynamicSlider并无法更改0-1的滚动条范围。而MyVector4_SupportDynamicSlider在按下Alt同时拖动鼠标后可以改变最小和最大的UI范围。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
在SPropertyEditorNumeric里并不会去提取SupportDynamicSliderMinValue该属性,因此默认情况下该值是不生效的。
|
||||
|
||||
```cpp
|
||||
void SPropertyEditorNumeric<NumericType>::Construct( const FArguments& InArgs, const TSharedRef<FPropertyEditor>& InPropertyEditor )
|
||||
{
|
||||
TNumericPropertyParams<NumericType> NumericPropertyParams(Property, MetaDataGetter);
|
||||
ChildSlot
|
||||
[
|
||||
SAssignNew(PrimaryWidget, SNumericEntryBox<NumericType>)
|
||||
// Only allow spinning if we have a single value
|
||||
.AllowSpin(bAllowSpin)
|
||||
.Value(this, &SPropertyEditorNumeric<NumericType>::OnGetValue)
|
||||
.Font(InArgs._Font)
|
||||
.MinValue(NumericPropertyParams.MinValue)
|
||||
.MaxValue(NumericPropertyParams.MaxValue)
|
||||
.MinSliderValue(NumericPropertyParams.MinSliderValue)
|
||||
.MaxSliderValue(NumericPropertyParams.MaxSliderValue)
|
||||
.SliderExponent(NumericPropertyParams.SliderExponent)
|
||||
.Delta(NumericPropertyParams.Delta)
|
||||
// LinearDeltaSensitivity needs to be left unset if not provided, rather than being set to some default
|
||||
.LinearDeltaSensitivity(NumericPropertyParams.GetLinearDeltaSensitivityAttribute())
|
||||
.AllowWheel(bAllowSpin)
|
||||
.WheelStep(NumericPropertyParams.WheelStep)
|
||||
.UndeterminedString(PropertyEditorConstants::DefaultUndeterminedText)
|
||||
.OnValueChanged(this, &SPropertyEditorNumeric<NumericType>::OnValueChanged)
|
||||
.OnValueCommitted(this, &SPropertyEditorNumeric<NumericType>::OnValueCommitted)
|
||||
.OnUndeterminedValueCommitted(this, &SPropertyEditorNumeric<NumericType>::OnUndeterminedValueCommitted)
|
||||
.OnBeginSliderMovement(this, &SPropertyEditorNumeric<NumericType>::OnBeginSliderMovement)
|
||||
.OnEndSliderMovement(this, &SPropertyEditorNumeric<NumericType>::OnEndSliderMovement)
|
||||
.TypeInterface(TypeInterface)
|
||||
];
|
||||
}
|
||||
|
||||
virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
|
||||
{
|
||||
if (MouseEvent.IsAltDown())
|
||||
{
|
||||
float DeltaToAdd = (float)MouseEvent.GetCursorDelta().X / SliderWidthInSlateUnits;
|
||||
|
||||
if (SupportDynamicSliderMaxValue.Get() && (NumericType)InternalValue == GetMaxSliderValue())
|
||||
{
|
||||
ApplySliderMaxValueChanged(DeltaToAdd, false);
|
||||
}
|
||||
else if (SupportDynamicSliderMinValue.Get() && (NumericType)InternalValue == GetMinSliderValue())
|
||||
{
|
||||
ApplySliderMinValueChanged(DeltaToAdd, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@@ -0,0 +1,9 @@
|
||||
# UIMax
|
||||
|
||||
- **功能描述:** 指定数字输入框上滚动条拖动的最大范围值
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [UIMin](UIMin/UIMin.md)
|
||||
- **常用程度:** ★★★★★
|
After Width: | Height: | Size: 323 KiB |
@@ -0,0 +1,146 @@
|
||||
# UIMin
|
||||
|
||||
- **功能描述:** 指定数字输入框上滚动条拖动的最小范围值
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [UIMax](../UIMax.md), [ClampMin](../ClampMin.md), [ClampMax](../ClampMax.md)
|
||||
- **常用程度:** ★★★★★
|
||||
|
||||
UIMin-UIMax和ClampMin-ClampMax的区别是,UI系列阻止用户在拖动鼠标的时候把值超过某个范围,但是用户依然可以手动输入超过这个范围的值。而Clamp系列是实际的值的范围限制,用户拖动或者手动输入值都不允许超过这个范围。
|
||||
|
||||
这两个限制都无法限制蓝图下直接修改值。
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest)
|
||||
float MyFloat_NoMinMax = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (UIMin = "0", UIMax = "100"))
|
||||
float MyFloat_HasMinMax_UI = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "0", ClampMax = "100"))
|
||||
float MyFloat_HasMinMax_Clamp = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "0", ClampMax = "100",UIMin = "20", UIMax = "50"))
|
||||
float MyFloat_HasMinMax_ClampAndUI = 100;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = MinMaxTest, meta = (ClampMin = "20", ClampMax = "50",UIMin = "0", UIMax = "100"))
|
||||
float MyFloat_HasMinMax_ClampAndUI2= 100;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
- 从MyFloat_HasMinMax_UI发现,UIMin, UIMax限制数字输入框滚动条的范围,但依然可以手动输入超过的值999
|
||||
- 从MyFloat_HasMinMax_Clamp 发现,ClampMin,ClampMax 会同时限制UI和手动输入的范围。
|
||||
- 从MyFloat_HasMinMax_ClampAndUI和MyFloat_HasMinMax_ClampAndUI2发现,UI的滚动条会取UI的限制和Clamp限制的更窄范围,而实际输入值也是会被限制在更窄的范围内。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
TNumericPropertyParams在构造的时候就会取得一些meta来初始化这些变量。否则就会成为默认值。
|
||||
|
||||
数值类型有实际的最小最大值(MinValue-MaxValue),是由ClampMin和ClampMax提供的。也有UI上的最小最大值(MinSliderValue-MaxSliderValue),是由Max(UImin,ClampMin)和Min(UIMax,ClampMax)提供的,即取最小的范围来保障合法输入。
|
||||
|
||||
```cpp
|
||||
template<typename NumericType>
|
||||
struct TNumericPropertyParams
|
||||
{
|
||||
if (MetaDataGetter.IsBound())
|
||||
{
|
||||
UIMinString = MetaDataGetter.Execute("UIMin");
|
||||
UIMaxString = MetaDataGetter.Execute("UIMax");
|
||||
SliderExponentString = MetaDataGetter.Execute("SliderExponent");
|
||||
LinearDeltaSensitivityString = MetaDataGetter.Execute("LinearDeltaSensitivity");
|
||||
DeltaString = MetaDataGetter.Execute("Delta");
|
||||
ClampMinString = MetaDataGetter.Execute("ClampMin");
|
||||
ClampMaxString = MetaDataGetter.Execute("ClampMax");
|
||||
ForcedUnits = MetaDataGetter.Execute("ForceUnits");
|
||||
WheelStepString = MetaDataGetter.Execute("WheelStep");
|
||||
}
|
||||
|
||||
TOptional<NumericType> MinValue;
|
||||
TOptional<NumericType> MaxValue;
|
||||
TOptional<NumericType> MinSliderValue;
|
||||
TOptional<NumericType> MaxSliderValue;
|
||||
NumericType SliderExponent;
|
||||
NumericType Delta;
|
||||
int32 LinearDeltaSensitivity;
|
||||
TOptional<NumericType> WheelStep;
|
||||
}
|
||||
//最终这些值会传输给
|
||||
SAssignNew(SpinBox, SSpinBox<NumericType>)
|
||||
.Style(InArgs._SpinBoxStyle)
|
||||
.Font(InArgs._Font.IsSet() ? InArgs._Font : InArgs._EditableTextBoxStyle->TextStyle.Font)
|
||||
.Value(this, &SNumericEntryBox<NumericType>::OnGetValueForSpinBox)
|
||||
.Delta(InArgs._Delta)
|
||||
.ShiftMultiplier(InArgs._ShiftMultiplier)
|
||||
.CtrlMultiplier(InArgs._CtrlMultiplier)
|
||||
.LinearDeltaSensitivity(InArgs._LinearDeltaSensitivity)
|
||||
.SupportDynamicSliderMaxValue(InArgs._SupportDynamicSliderMaxValue)
|
||||
.SupportDynamicSliderMinValue(InArgs._SupportDynamicSliderMinValue)
|
||||
.OnDynamicSliderMaxValueChanged(InArgs._OnDynamicSliderMaxValueChanged)
|
||||
.OnDynamicSliderMinValueChanged(InArgs._OnDynamicSliderMinValueChanged)
|
||||
.OnValueChanged(OnValueChanged)
|
||||
.OnValueCommitted(OnValueCommitted)
|
||||
.MinFractionalDigits(MinFractionalDigits)
|
||||
.MaxFractionalDigits(MaxFractionalDigits)
|
||||
.MinSliderValue(InArgs._MinSliderValue)
|
||||
.MaxSliderValue(InArgs._MaxSliderValue)
|
||||
.MaxValue(InArgs._MaxValue)
|
||||
.MinValue(InArgs._MinValue)
|
||||
.SliderExponent(InArgs._SliderExponent)
|
||||
.SliderExponentNeutralValue(InArgs._SliderExponentNeutralValue)
|
||||
.EnableWheel(InArgs._AllowWheel)
|
||||
.BroadcastValueChangesPerKey(InArgs._BroadcastValueChangesPerKey)
|
||||
.WheelStep(InArgs._WheelStep)
|
||||
.OnBeginSliderMovement(InArgs._OnBeginSliderMovement)
|
||||
.OnEndSliderMovement(InArgs._OnEndSliderMovement)
|
||||
.MinDesiredWidth(InArgs._MinDesiredValueWidth)
|
||||
.TypeInterface(Interface)
|
||||
.ToolTipText(this, &SNumericEntryBox<NumericType>::GetValueAsText);
|
||||
|
||||
|
||||
//最后
|
||||
void SSpinBox<NumericType>::CommitValue(NumericType NewValue, double NewSpinValue, ECommitMethod CommitMethod, ETextCommit::Type OriginalCommitInfo)
|
||||
{
|
||||
if (CommitMethod == CommittedViaSpin || CommitMethod == CommittedViaArrowKey)
|
||||
{
|
||||
const NumericType LocalMinSliderValue = GetMinSliderValue();
|
||||
const NumericType LocalMaxSliderValue = GetMaxSliderValue();
|
||||
NewValue = FMath::Clamp<NumericType>(NewValue, LocalMinSliderValue, LocalMaxSliderValue);
|
||||
NewSpinValue = FMath::Clamp<double>(NewSpinValue, (double)LocalMinSliderValue, (double)LocalMaxSliderValue);
|
||||
}
|
||||
|
||||
{
|
||||
const NumericType LocalMinValue = GetMinValue();
|
||||
const NumericType LocalMaxValue = GetMaxValue();
|
||||
NewValue = FMath::Clamp<NumericType>(NewValue, LocalMinValue, LocalMaxValue);
|
||||
NewSpinValue = FMath::Clamp<double>(NewSpinValue, (double)LocalMinValue, (double)LocalMaxValue);
|
||||
}
|
||||
|
||||
// Update the internal value, this needs to be done before rounding.
|
||||
InternalValue = NewSpinValue;
|
||||
|
||||
const bool bAlwaysUsesDeltaSnap = GetAlwaysUsesDeltaSnap();
|
||||
// If needed, round this value to the delta. Internally the value is not held to the Delta but externally it appears to be.
|
||||
if (CommitMethod == CommittedViaSpin || CommitMethod == CommittedViaArrowKey || bAlwaysUsesDeltaSnap)
|
||||
{
|
||||
NumericType CurrentDelta = Delta.Get();
|
||||
if (CurrentDelta != NumericType())
|
||||
{
|
||||
NewValue = FMath::GridSnap<NumericType>(NewValue, CurrentDelta); // snap numeric point value to nearest Delta
|
||||
}
|
||||
}
|
||||
|
||||
// Update the max slider value based on the current value if we're in dynamic mode
|
||||
if (SupportDynamicSliderMaxValue.Get() && ValueAttribute.Get() > GetMaxSliderValue())
|
||||
{
|
||||
ApplySliderMaxValueChanged(float(ValueAttribute.Get() - GetMaxSliderValue()), true);
|
||||
}
|
||||
else if (SupportDynamicSliderMinValue.Get() && ValueAttribute.Get() < GetMinSliderValue())
|
||||
{
|
||||
ApplySliderMinValueChanged(float(ValueAttribute.Get() - GetMinSliderValue()), true);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
After Width: | Height: | Size: 3.5 MiB |
@@ -0,0 +1,128 @@
|
||||
# Units
|
||||
|
||||
- **功能描述:** 设定属性值的单位,支持实时根据数值不同动态改变显示的单位。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** string="abc"
|
||||
- **限制类型:** float,int32
|
||||
- **关联项:** [ForceUnits](../ForceUnits.md)
|
||||
- **常用程度:** ★★★
|
||||
|
||||
设定属性值的单位。一个单位有多个别名,如Kilograms和kg,Centimeters和cm,都是可以的。
|
||||
|
||||
Units的作用不光是设定单位,而且隐含着这个显示的单位字符串可以根据用户输入的数值自动的进行调整适应。比如100cm其实就是1m,0.5km就是500m。
|
||||
|
||||
另外设定了单位之后,还可以接受用户直接在数字框中输入数字和单位的组合,比如直接敲入1km就可以设置值为1,单位为km。或者1ft为1英尺=30.84cm。
|
||||
|
||||
要实现自动的调整显示单位的功能,首先需要在项目设置里设置单位系列。比如下图就在距离上设置了厘米,米,千米,毫米的单位(顺序不重要)。然后之后数字框显示距离的单位时就可以在这4者之间转换。
|
||||
|
||||

|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, Category = UnitsTest)
|
||||
float MyFloat_NoUnits = 0.0;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = UnitsTest, Meta = (Units = "cm"))
|
||||
float MyFloat_HasUnits_Distance = 100.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = UnitsTest, Meta = (ForceUnits = "cm"))
|
||||
float MyFloat_HasForceUnits_Distance = 100.f;
|
||||
```
|
||||
|
||||
## 测试效果:
|
||||
|
||||
- 在项目设置里填入4个单位:cm,m,km,mm后开始测试。
|
||||
- 发现采用Units的属性,会自动的根据值的不同调整单位。而且也接受数字+单位的输入。
|
||||
- 发现采用ForceUnits的属性,也可以接受数字+单位的输入,但是在显示上却始终显示为cm,不会调整到别的单位。
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
- 如果ForcedUnits有设置,则会同时设置UnderlyingUnits(基础单位),UserDisplayUnits 和FixedDisplayUnits 。
|
||||
- 否则如果设置Units,则会只设置到UnderlyingUnits和FixedDisplayUnits
|
||||
- 最后在显示单位的时候,如果有UserDisplayUnits,则优先采用。之后才是FixedDisplayUnits 。
|
||||
- ToString的时候,是把UnderlyingUnits转到UserDisplayUnits或FixedDisplayUnits。
|
||||
- 在数字输入框改变的时候,会触发SetupFixedDisplay,从而在内部每次重新计算合适的单位赋值到FixedDisplayUnits。因此如上面说的,如果没有设置UserDisplayUnits(没有ForceUnits),则每次都会调整到新的合适显示单位。否则就会因为UserDisplayUnits优先级最高且一直有值,导致总是以UserDisplayUnits显示保持不变。
|
||||
|
||||
```cpp
|
||||
void SPropertyEditorNumeric<NumericType>::Construct( const FArguments& InArgs, const TSharedRef<FPropertyEditor>& InPropertyEditor )
|
||||
{
|
||||
// First off, check for ForceUnits= meta data. This meta tag tells us to interpret, and always display the value in these units. FUnitConversion::Settings().ShouldDisplayUnits does not apply to such properties
|
||||
const FString& ForcedUnits = MetaDataGetter.Execute("ForceUnits");
|
||||
TOptional<EUnit> PropertyUnits = FUnitConversion::UnitFromString(*ForcedUnits);
|
||||
if (PropertyUnits.IsSet())
|
||||
{
|
||||
// Create the type interface and set up the default input units if they are compatible
|
||||
TypeInterface = MakeShareable(new TNumericUnitTypeInterface<NumericType>(PropertyUnits.GetValue()));
|
||||
TypeInterface->UserDisplayUnits = TypeInterface->FixedDisplayUnits = PropertyUnits.GetValue();
|
||||
}
|
||||
// If that's not set, we fall back to Units=xxx which calculates the most appropriate unit to display in
|
||||
else
|
||||
{
|
||||
if (FUnitConversion::Settings().ShouldDisplayUnits())
|
||||
{
|
||||
const FString& DynamicUnits = PropertyHandle->GetMetaData(TEXT("Units"));
|
||||
if (!DynamicUnits.IsEmpty())
|
||||
{
|
||||
PropertyUnits = FUnitConversion::UnitFromString(*DynamicUnits);
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyUnits = FUnitConversion::UnitFromString(*MetaDataGetter.Execute("Units"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!PropertyUnits.IsSet())
|
||||
{
|
||||
PropertyUnits = EUnit::Unspecified;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPropertyEditorNumeric<NumericType>::OnValueCommitted( NumericType NewValue, ETextCommit::Type CommitInfo )
|
||||
{
|
||||
|
||||
if (TypeInterface.IsValid())
|
||||
{
|
||||
TypeInterface->SetupFixedDisplay(NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename NumericType>
|
||||
void TNumericUnitTypeInterface<NumericType>::SetupFixedDisplay(const NumericType& InValue)
|
||||
{
|
||||
// We calculate this regardless of whether FixedDisplayUnits is used, so that the moment it is used, it's correct
|
||||
EUnit DisplayUnit = FUnitConversion::CalculateDisplayUnit(InValue, UnderlyingUnits);
|
||||
if (DisplayUnit != EUnit::Unspecified)
|
||||
{
|
||||
FixedDisplayUnits = DisplayUnit;
|
||||
}
|
||||
}
|
||||
|
||||
//在转换的时候
|
||||
FString TNumericUnitTypeInterface<NumericType>::ToString(const NumericType& Value) const
|
||||
{
|
||||
if (UserDisplayUnits.IsSet())
|
||||
{
|
||||
auto Converted = FinalValue.ConvertTo(UserDisplayUnits.GetValue());
|
||||
if (Converted.IsSet())
|
||||
{
|
||||
return ToUnitString(Converted.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (FixedDisplayUnits.IsSet())
|
||||
{
|
||||
auto Converted = FinalValue.ConvertTo(FixedDisplayUnits.GetValue());
|
||||
if (Converted.IsSet())
|
||||
{
|
||||
return ToUnitString(Converted.GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
After Width: | Height: | Size: 280 KiB |
@@ -0,0 +1,76 @@
|
||||
# WheelStep
|
||||
|
||||
- **功能描述:** 指定数字输入框上鼠标轮上下滚动产生的变化值
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** float/int
|
||||
- **常用程度:** ★★★
|
||||
|
||||
指定数字输入框上鼠标轮上下滚动产生的变化值。
|
||||
|
||||
## 默认值的规则:
|
||||
|
||||
如果属性是浮点数且UI滚动条范围小于10,则WheelStep=0.1,否则为1
|
||||
|
||||
如果属性是整数,则WheelStep=1
|
||||
|
||||
## 测试代码:
|
||||
|
||||
```cpp
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WheelStepTest)
|
||||
float MyFloat_DefaultWheelStep = 50;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WheelStepTest, meta = (UIMin = "0", UIMax = "10"))
|
||||
float MyFloat_SmallWheelStep = 1;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WheelStepTest, meta = (WheelStep = 10))
|
||||
float MyFloat_HasWheelStep = 50;
|
||||
```
|
||||
|
||||
## 效果图:
|
||||
|
||||
默认值不指定UIMin,UIMax也可以鼠标轮滚动变化值。默认为1
|
||||
|
||||
MyFloat_SmallWheelStep的UI范围只有10,则默认改变幅度0.1
|
||||
|
||||
指定WheelStep =10,则一下子变化10
|
||||
|
||||

|
||||
|
||||
## 原理:
|
||||
|
||||
通过代码可知,如果设置了WheelStep则用该值。
|
||||
|
||||
否则如果是浮点数且UI滚动条范围小于10,则WheelStep=0.1,否则为1
|
||||
|
||||
否则如果是整数,则WheelStep=1
|
||||
|
||||
```cpp
|
||||
virtual FReply SSpinBox<NumericType>::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override
|
||||
{
|
||||
if (bEnableWheel && PointerDraggingSliderIndex == INDEX_NONE && HasKeyboardFocus())
|
||||
{
|
||||
// If there is no WheelStep defined, we use 1.0 (Or 0.1 if slider range is <= 10)
|
||||
constexpr bool bIsIntegral = TIsIntegral<NumericType>::Value;
|
||||
const bool bIsSmallStep = !bIsIntegral && (GetMaxSliderValue() - GetMinSliderValue()) <= 10.0;
|
||||
double Step = WheelStep.IsSet() && WheelStep.Get().IsSet() ? WheelStep.Get().GetValue() : (bIsSmallStep ? 0.1 : 1.0);
|
||||
|
||||
if (MouseEvent.IsControlDown())
|
||||
{
|
||||
// If no value is set for WheelSmallStep, we use the DefaultStep multiplied by the CtrlMultiplier
|
||||
Step *= CtrlMultiplier.Get();
|
||||
}
|
||||
else if (MouseEvent.IsShiftDown())
|
||||
{
|
||||
// If no value is set for WheelBigStep, we use the DefaultStep multiplied by the ShiftMultiplier
|
||||
Step *= ShiftMultiplier.Get();
|
||||
}
|
||||
|
||||
const double Sign = (MouseEvent.GetWheelDelta() > 0) ? 1.0 : -1.0;
|
||||
const double NewValue = InternalValue + (Sign * Step);
|
||||
const NumericType RoundedNewValue = RoundIfIntegerValue(NewValue);
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
return FReply::Unhandled();
|
||||
}
|
||||
```
|
After Width: | Height: | Size: 219 KiB |
@@ -0,0 +1,26 @@
|
||||
# sRGB
|
||||
|
||||
- **功能描述:** 使FColor或FLinearColor属性在编辑的时候采用sRGB方式。
|
||||
- **使用位置:** UPROPERTY
|
||||
- **引擎模块:** Numeric Property
|
||||
- **元数据类型:** bool
|
||||
- **限制类型:** FColor , FLinearColor
|
||||
|
||||
使FColor或FLinearColor属性在编辑的时候采用sRGB方式。
|
||||
|
||||
但是在测试的时候并无法工作。
|
||||
|
||||
## 原理:
|
||||
|
||||
```cpp
|
||||
void FColorStructCustomization::CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& InHeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils)
|
||||
{
|
||||
|
||||
if (StructPropertyHandle->GetProperty()->HasMetaData(TEXT("sRGB")))
|
||||
{
|
||||
sRGBOverride = StructPropertyHandle->GetProperty()->GetBoolMetaData(TEXT("sRGB"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|